1use super::Database;
2use crate::db::ExtensionVersionConstraints;
3use crate::{
4 db::{queries::extensions::convert_time_to_chrono, ExtensionMetadata, NewExtensionVersion},
5 test_both_dbs,
6};
7use std::sync::Arc;
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, 1, 5).await.unwrap();
20 assert!(extensions.is_empty());
21
22 let t0 = time::OffsetDateTime::from_unix_timestamp_nanos(0).unwrap();
23 let t0 = time::PrimitiveDateTime::new(t0.date(), t0.time());
24
25 let t0_chrono = convert_time_to_chrono(t0);
26
27 db.insert_extension_versions(
28 &[
29 (
30 "ext1",
31 vec![
32 NewExtensionVersion {
33 name: "Extension 1".into(),
34 version: semver::Version::parse("0.0.1").unwrap(),
35 description: "an extension".into(),
36 authors: vec!["max".into()],
37 repository: "ext1/repo".into(),
38 schema_version: 1,
39 wasm_api_version: None,
40 published_at: t0,
41 },
42 NewExtensionVersion {
43 name: "Extension One".into(),
44 version: semver::Version::parse("0.0.2").unwrap(),
45 description: "a good extension".into(),
46 authors: vec!["max".into(), "marshall".into()],
47 repository: "ext1/repo".into(),
48 schema_version: 1,
49 wasm_api_version: None,
50 published_at: t0,
51 },
52 ],
53 ),
54 (
55 "ext2",
56 vec![NewExtensionVersion {
57 name: "Extension Two".into(),
58 version: semver::Version::parse("0.2.0").unwrap(),
59 description: "a great extension".into(),
60 authors: vec!["marshall".into()],
61 repository: "ext2/repo".into(),
62 schema_version: 0,
63 wasm_api_version: None,
64 published_at: t0,
65 }],
66 ),
67 ]
68 .into_iter()
69 .collect(),
70 )
71 .await
72 .unwrap();
73
74 let versions = db.get_known_extension_versions().await.unwrap();
75 assert_eq!(
76 versions,
77 [
78 ("ext1".into(), vec!["0.0.1".into(), "0.0.2".into()]),
79 ("ext2".into(), vec!["0.2.0".into()])
80 ]
81 .into_iter()
82 .collect()
83 );
84
85 // The latest version of each extension is returned.
86 let extensions = db.get_extensions(None, 1, 5).await.unwrap();
87 assert_eq!(
88 extensions,
89 &[
90 ExtensionMetadata {
91 id: "ext1".into(),
92 manifest: rpc::ExtensionApiManifest {
93 name: "Extension One".into(),
94 version: "0.0.2".into(),
95 authors: vec!["max".into(), "marshall".into()],
96 description: Some("a good extension".into()),
97 repository: "ext1/repo".into(),
98 schema_version: Some(1),
99 wasm_api_version: None,
100 },
101 published_at: t0_chrono,
102 download_count: 0,
103 },
104 ExtensionMetadata {
105 id: "ext2".into(),
106 manifest: rpc::ExtensionApiManifest {
107 name: "Extension Two".into(),
108 version: "0.2.0".into(),
109 authors: vec!["marshall".into()],
110 description: Some("a great extension".into()),
111 repository: "ext2/repo".into(),
112 schema_version: Some(0),
113 wasm_api_version: None,
114 },
115 published_at: t0_chrono,
116 download_count: 0
117 },
118 ]
119 );
120
121 // Extensions with too new of a schema version are excluded.
122 let extensions = db.get_extensions(None, 0, 5).await.unwrap();
123 assert_eq!(
124 extensions,
125 &[ExtensionMetadata {
126 id: "ext2".into(),
127 manifest: rpc::ExtensionApiManifest {
128 name: "Extension Two".into(),
129 version: "0.2.0".into(),
130 authors: vec!["marshall".into()],
131 description: Some("a great extension".into()),
132 repository: "ext2/repo".into(),
133 schema_version: Some(0),
134 wasm_api_version: None,
135 },
136 published_at: t0_chrono,
137 download_count: 0
138 },]
139 );
140
141 // Record extensions being downloaded.
142 for _ in 0..7 {
143 assert!(db.record_extension_download("ext2", "0.0.2").await.unwrap());
144 }
145
146 for _ in 0..3 {
147 assert!(db.record_extension_download("ext1", "0.0.1").await.unwrap());
148 }
149
150 for _ in 0..2 {
151 assert!(db.record_extension_download("ext1", "0.0.2").await.unwrap());
152 }
153
154 // Record download returns false if the extension does not exist.
155 assert!(!db
156 .record_extension_download("no-such-extension", "0.0.2")
157 .await
158 .unwrap());
159
160 // Extensions are returned in descending order of total downloads.
161 let extensions = db.get_extensions(None, 1, 5).await.unwrap();
162 assert_eq!(
163 extensions,
164 &[
165 ExtensionMetadata {
166 id: "ext2".into(),
167 manifest: rpc::ExtensionApiManifest {
168 name: "Extension Two".into(),
169 version: "0.2.0".into(),
170 authors: vec!["marshall".into()],
171 description: Some("a great extension".into()),
172 repository: "ext2/repo".into(),
173 schema_version: Some(0),
174 wasm_api_version: None,
175 },
176 published_at: t0_chrono,
177 download_count: 7
178 },
179 ExtensionMetadata {
180 id: "ext1".into(),
181 manifest: rpc::ExtensionApiManifest {
182 name: "Extension One".into(),
183 version: "0.0.2".into(),
184 authors: vec!["max".into(), "marshall".into()],
185 description: Some("a good extension".into()),
186 repository: "ext1/repo".into(),
187 schema_version: Some(1),
188 wasm_api_version: None,
189 },
190 published_at: t0_chrono,
191 download_count: 5,
192 },
193 ]
194 );
195
196 // Add more extensions, including a new version of `ext1`, and backfilling
197 // an older version of `ext2`.
198 db.insert_extension_versions(
199 &[
200 (
201 "ext1",
202 vec![NewExtensionVersion {
203 name: "Extension One".into(),
204 version: semver::Version::parse("0.0.3").unwrap(),
205 description: "a real good extension".into(),
206 authors: vec!["max".into(), "marshall".into()],
207 repository: "ext1/repo".into(),
208 schema_version: 1,
209 wasm_api_version: None,
210 published_at: t0,
211 }],
212 ),
213 (
214 "ext2",
215 vec![NewExtensionVersion {
216 name: "Extension Two".into(),
217 version: semver::Version::parse("0.1.0").unwrap(),
218 description: "an old extension".into(),
219 authors: vec!["marshall".into()],
220 repository: "ext2/repo".into(),
221 schema_version: 0,
222 wasm_api_version: None,
223 published_at: t0,
224 }],
225 ),
226 ]
227 .into_iter()
228 .collect(),
229 )
230 .await
231 .unwrap();
232
233 let versions = db.get_known_extension_versions().await.unwrap();
234 assert_eq!(
235 versions,
236 [
237 (
238 "ext1".into(),
239 vec!["0.0.1".into(), "0.0.2".into(), "0.0.3".into()]
240 ),
241 ("ext2".into(), vec!["0.1.0".into(), "0.2.0".into()])
242 ]
243 .into_iter()
244 .collect()
245 );
246
247 let extensions = db.get_extensions(None, 1, 5).await.unwrap();
248 assert_eq!(
249 extensions,
250 &[
251 ExtensionMetadata {
252 id: "ext2".into(),
253 manifest: rpc::ExtensionApiManifest {
254 name: "Extension Two".into(),
255 version: "0.2.0".into(),
256 authors: vec!["marshall".into()],
257 description: Some("a great extension".into()),
258 repository: "ext2/repo".into(),
259 schema_version: Some(0),
260 wasm_api_version: None,
261 },
262 published_at: t0_chrono,
263 download_count: 7
264 },
265 ExtensionMetadata {
266 id: "ext1".into(),
267 manifest: rpc::ExtensionApiManifest {
268 name: "Extension One".into(),
269 version: "0.0.3".into(),
270 authors: vec!["max".into(), "marshall".into()],
271 description: Some("a real good extension".into()),
272 repository: "ext1/repo".into(),
273 schema_version: Some(1),
274 wasm_api_version: None,
275 },
276 published_at: t0_chrono,
277 download_count: 5,
278 },
279 ]
280 );
281}
282
283test_both_dbs!(
284 test_extensions_by_id,
285 test_extensions_by_id_postgres,
286 test_extensions_by_id_sqlite
287);
288
289async fn test_extensions_by_id(db: &Arc<Database>) {
290 let versions = db.get_known_extension_versions().await.unwrap();
291 assert!(versions.is_empty());
292
293 let extensions = db.get_extensions(None, 1, 5).await.unwrap();
294 assert!(extensions.is_empty());
295
296 let t0 = time::OffsetDateTime::from_unix_timestamp_nanos(0).unwrap();
297 let t0 = time::PrimitiveDateTime::new(t0.date(), t0.time());
298
299 let t0_chrono = convert_time_to_chrono(t0);
300
301 db.insert_extension_versions(
302 &[
303 (
304 "ext1",
305 vec![
306 NewExtensionVersion {
307 name: "Extension 1".into(),
308 version: semver::Version::parse("0.0.1").unwrap(),
309 description: "an extension".into(),
310 authors: vec!["max".into()],
311 repository: "ext1/repo".into(),
312 schema_version: 1,
313 wasm_api_version: Some("0.0.4".into()),
314 published_at: t0,
315 },
316 NewExtensionVersion {
317 name: "Extension 1".into(),
318 version: semver::Version::parse("0.0.2").unwrap(),
319 description: "a good extension".into(),
320 authors: vec!["max".into()],
321 repository: "ext1/repo".into(),
322 schema_version: 1,
323 wasm_api_version: Some("0.0.4".into()),
324 published_at: t0,
325 },
326 NewExtensionVersion {
327 name: "Extension 1".into(),
328 version: semver::Version::parse("0.0.3").unwrap(),
329 description: "a real good extension".into(),
330 authors: vec!["max".into(), "marshall".into()],
331 repository: "ext1/repo".into(),
332 schema_version: 1,
333 wasm_api_version: Some("0.0.5".into()),
334 published_at: t0,
335 },
336 ],
337 ),
338 (
339 "ext2",
340 vec![NewExtensionVersion {
341 name: "Extension 2".into(),
342 version: semver::Version::parse("0.2.0").unwrap(),
343 description: "a great extension".into(),
344 authors: vec!["marshall".into()],
345 repository: "ext2/repo".into(),
346 schema_version: 0,
347 wasm_api_version: None,
348 published_at: t0,
349 }],
350 ),
351 ]
352 .into_iter()
353 .collect(),
354 )
355 .await
356 .unwrap();
357
358 let extensions = db
359 .get_extensions_by_ids(
360 &["ext1"],
361 Some(&ExtensionVersionConstraints {
362 schema_versions: 1..=1,
363 wasm_api_versions: "0.0.1".parse().unwrap()..="0.0.4".parse().unwrap(),
364 }),
365 )
366 .await
367 .unwrap();
368
369 assert_eq!(
370 extensions,
371 &[ExtensionMetadata {
372 id: "ext1".into(),
373 manifest: rpc::ExtensionApiManifest {
374 name: "Extension 1".into(),
375 version: "0.0.2".into(),
376 authors: vec!["max".into()],
377 description: Some("a good extension".into()),
378 repository: "ext1/repo".into(),
379 schema_version: Some(1),
380 wasm_api_version: Some("0.0.4".into()),
381 },
382 published_at: t0_chrono,
383 download_count: 0,
384 }]
385 );
386}