1use super::Database;
2use crate::{
3 db::{ExtensionMetadata, NewExtensionVersion},
4 test_both_dbs,
5};
6use std::sync::Arc;
7use time::{OffsetDateTime, PrimitiveDateTime};
8
9test_both_dbs!(
10 test_extensions,
11 test_extensions_postgres,
12 test_extensions_sqlite
13);
14
15async fn test_extensions(db: &Arc<Database>) {
16 let versions = db.get_known_extension_versions().await.unwrap();
17 assert!(versions.is_empty());
18
19 let extensions = db.get_extensions(None, 5).await.unwrap();
20 assert!(extensions.is_empty());
21
22 let t0 = OffsetDateTime::from_unix_timestamp_nanos(0).unwrap();
23 let t0 = PrimitiveDateTime::new(t0.date(), t0.time());
24
25 db.insert_extension_versions(
26 &[
27 (
28 "ext1",
29 vec![
30 NewExtensionVersion {
31 name: "Extension 1".into(),
32 version: semver::Version::parse("0.0.1").unwrap(),
33 description: "an extension".into(),
34 authors: vec!["max".into()],
35 repository: "ext1/repo".into(),
36 published_at: t0,
37 },
38 NewExtensionVersion {
39 name: "Extension One".into(),
40 version: semver::Version::parse("0.0.2").unwrap(),
41 description: "a good extension".into(),
42 authors: vec!["max".into(), "marshall".into()],
43 repository: "ext1/repo".into(),
44 published_at: t0,
45 },
46 ],
47 ),
48 (
49 "ext2",
50 vec![NewExtensionVersion {
51 name: "Extension Two".into(),
52 version: semver::Version::parse("0.2.0").unwrap(),
53 description: "a great extension".into(),
54 authors: vec!["marshall".into()],
55 repository: "ext2/repo".into(),
56 published_at: t0,
57 }],
58 ),
59 ]
60 .into_iter()
61 .collect(),
62 )
63 .await
64 .unwrap();
65
66 let versions = db.get_known_extension_versions().await.unwrap();
67 assert_eq!(
68 versions,
69 [
70 ("ext1".into(), vec!["0.0.1".into(), "0.0.2".into()]),
71 ("ext2".into(), vec!["0.2.0".into()])
72 ]
73 .into_iter()
74 .collect()
75 );
76
77 // The latest version of each extension is returned.
78 let extensions = db.get_extensions(None, 5).await.unwrap();
79 assert_eq!(
80 extensions,
81 &[
82 ExtensionMetadata {
83 id: "ext1".into(),
84 name: "Extension One".into(),
85 version: "0.0.2".into(),
86 authors: vec!["max".into(), "marshall".into()],
87 repository: "ext1/repo".into(),
88 published_at: t0,
89 download_count: 0,
90 },
91 ExtensionMetadata {
92 id: "ext2".into(),
93 name: "Extension Two".into(),
94 version: "0.2.0".into(),
95 authors: vec!["marshall".into()],
96 repository: "ext2/repo".into(),
97 published_at: t0,
98 download_count: 0
99 },
100 ]
101 );
102
103 // Record extensions being downloaded.
104 for _ in 0..7 {
105 assert!(db.record_extension_download("ext2", "0.0.2").await.unwrap());
106 }
107
108 for _ in 0..3 {
109 assert!(db.record_extension_download("ext1", "0.0.1").await.unwrap());
110 }
111
112 for _ in 0..2 {
113 assert!(db.record_extension_download("ext1", "0.0.2").await.unwrap());
114 }
115
116 // Record download returns false if the extension does not exist.
117 assert!(!db
118 .record_extension_download("no-such-extension", "0.0.2")
119 .await
120 .unwrap());
121
122 // Extensions are returned in descending order of total downloads.
123 let extensions = db.get_extensions(None, 5).await.unwrap();
124 assert_eq!(
125 extensions,
126 &[
127 ExtensionMetadata {
128 id: "ext2".into(),
129 name: "Extension Two".into(),
130 version: "0.2.0".into(),
131 authors: vec!["marshall".into()],
132 repository: "ext2/repo".into(),
133 published_at: t0,
134 download_count: 7
135 },
136 ExtensionMetadata {
137 id: "ext1".into(),
138 name: "Extension One".into(),
139 version: "0.0.2".into(),
140 authors: vec!["max".into(), "marshall".into()],
141 repository: "ext1/repo".into(),
142 published_at: t0,
143 download_count: 5,
144 },
145 ]
146 );
147
148 // Add more extensions, including a new version of `ext1`, and backfilling
149 // an older version of `ext2`.
150 db.insert_extension_versions(
151 &[
152 (
153 "ext1",
154 vec![NewExtensionVersion {
155 name: "Extension One".into(),
156 version: semver::Version::parse("0.0.3").unwrap(),
157 description: "a real good extension".into(),
158 authors: vec!["max".into(), "marshall".into()],
159 repository: "ext1/repo".into(),
160 published_at: t0,
161 }],
162 ),
163 (
164 "ext2",
165 vec![NewExtensionVersion {
166 name: "Extension Two".into(),
167 version: semver::Version::parse("0.1.0").unwrap(),
168 description: "an old extension".into(),
169 authors: vec!["marshall".into()],
170 repository: "ext2/repo".into(),
171 published_at: t0,
172 }],
173 ),
174 ]
175 .into_iter()
176 .collect(),
177 )
178 .await
179 .unwrap();
180
181 let versions = db.get_known_extension_versions().await.unwrap();
182 assert_eq!(
183 versions,
184 [
185 (
186 "ext1".into(),
187 vec!["0.0.1".into(), "0.0.2".into(), "0.0.3".into()]
188 ),
189 ("ext2".into(), vec!["0.1.0".into(), "0.2.0".into()])
190 ]
191 .into_iter()
192 .collect()
193 );
194
195 let extensions = db.get_extensions(None, 5).await.unwrap();
196 assert_eq!(
197 extensions,
198 &[
199 ExtensionMetadata {
200 id: "ext2".into(),
201 name: "Extension Two".into(),
202 version: "0.2.0".into(),
203 authors: vec!["marshall".into()],
204 repository: "ext2/repo".into(),
205 published_at: t0,
206 download_count: 7
207 },
208 ExtensionMetadata {
209 id: "ext1".into(),
210 name: "Extension One".into(),
211 version: "0.0.3".into(),
212 authors: vec!["max".into(), "marshall".into()],
213 repository: "ext1/repo".into(),
214 published_at: t0,
215 download_count: 5,
216 },
217 ]
218 );
219}