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, 1, 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 schema_version: 1,
37 published_at: t0,
38 },
39 NewExtensionVersion {
40 name: "Extension One".into(),
41 version: semver::Version::parse("0.0.2").unwrap(),
42 description: "a good extension".into(),
43 authors: vec!["max".into(), "marshall".into()],
44 repository: "ext1/repo".into(),
45 schema_version: 1,
46 published_at: t0,
47 },
48 ],
49 ),
50 (
51 "ext2",
52 vec![NewExtensionVersion {
53 name: "Extension Two".into(),
54 version: semver::Version::parse("0.2.0").unwrap(),
55 description: "a great extension".into(),
56 authors: vec!["marshall".into()],
57 repository: "ext2/repo".into(),
58 schema_version: 0,
59 published_at: t0,
60 }],
61 ),
62 ]
63 .into_iter()
64 .collect(),
65 )
66 .await
67 .unwrap();
68
69 let versions = db.get_known_extension_versions().await.unwrap();
70 assert_eq!(
71 versions,
72 [
73 ("ext1".into(), vec!["0.0.1".into(), "0.0.2".into()]),
74 ("ext2".into(), vec!["0.2.0".into()])
75 ]
76 .into_iter()
77 .collect()
78 );
79
80 // The latest version of each extension is returned.
81 let extensions = db.get_extensions(None, 1, 5).await.unwrap();
82 assert_eq!(
83 extensions,
84 &[
85 ExtensionMetadata {
86 id: "ext1".into(),
87 name: "Extension One".into(),
88 version: "0.0.2".into(),
89 authors: vec!["max".into(), "marshall".into()],
90 description: "a good extension".into(),
91 repository: "ext1/repo".into(),
92 published_at: t0,
93 download_count: 0,
94 },
95 ExtensionMetadata {
96 id: "ext2".into(),
97 name: "Extension Two".into(),
98 version: "0.2.0".into(),
99 authors: vec!["marshall".into()],
100 description: "a great extension".into(),
101 repository: "ext2/repo".into(),
102 published_at: t0,
103 download_count: 0
104 },
105 ]
106 );
107
108 // Extensions with too new of a schema version are excluded.
109 let extensions = db.get_extensions(None, 0, 5).await.unwrap();
110 assert_eq!(
111 extensions,
112 &[ExtensionMetadata {
113 id: "ext2".into(),
114 name: "Extension Two".into(),
115 version: "0.2.0".into(),
116 authors: vec!["marshall".into()],
117 description: "a great extension".into(),
118 repository: "ext2/repo".into(),
119 published_at: t0,
120 download_count: 0
121 },]
122 );
123
124 // Record extensions being downloaded.
125 for _ in 0..7 {
126 assert!(db.record_extension_download("ext2", "0.0.2").await.unwrap());
127 }
128
129 for _ in 0..3 {
130 assert!(db.record_extension_download("ext1", "0.0.1").await.unwrap());
131 }
132
133 for _ in 0..2 {
134 assert!(db.record_extension_download("ext1", "0.0.2").await.unwrap());
135 }
136
137 // Record download returns false if the extension does not exist.
138 assert!(!db
139 .record_extension_download("no-such-extension", "0.0.2")
140 .await
141 .unwrap());
142
143 // Extensions are returned in descending order of total downloads.
144 let extensions = db.get_extensions(None, 1, 5).await.unwrap();
145 assert_eq!(
146 extensions,
147 &[
148 ExtensionMetadata {
149 id: "ext2".into(),
150 name: "Extension Two".into(),
151 version: "0.2.0".into(),
152 authors: vec!["marshall".into()],
153 description: "a great extension".into(),
154 repository: "ext2/repo".into(),
155 published_at: t0,
156 download_count: 7
157 },
158 ExtensionMetadata {
159 id: "ext1".into(),
160 name: "Extension One".into(),
161 version: "0.0.2".into(),
162 authors: vec!["max".into(), "marshall".into()],
163 description: "a good extension".into(),
164 repository: "ext1/repo".into(),
165 published_at: t0,
166 download_count: 5,
167 },
168 ]
169 );
170
171 // Add more extensions, including a new version of `ext1`, and backfilling
172 // an older version of `ext2`.
173 db.insert_extension_versions(
174 &[
175 (
176 "ext1",
177 vec![NewExtensionVersion {
178 name: "Extension One".into(),
179 version: semver::Version::parse("0.0.3").unwrap(),
180 description: "a real good extension".into(),
181 authors: vec!["max".into(), "marshall".into()],
182 repository: "ext1/repo".into(),
183 schema_version: 1,
184 published_at: t0,
185 }],
186 ),
187 (
188 "ext2",
189 vec![NewExtensionVersion {
190 name: "Extension Two".into(),
191 version: semver::Version::parse("0.1.0").unwrap(),
192 description: "an old extension".into(),
193 authors: vec!["marshall".into()],
194 repository: "ext2/repo".into(),
195 schema_version: 0,
196 published_at: t0,
197 }],
198 ),
199 ]
200 .into_iter()
201 .collect(),
202 )
203 .await
204 .unwrap();
205
206 let versions = db.get_known_extension_versions().await.unwrap();
207 assert_eq!(
208 versions,
209 [
210 (
211 "ext1".into(),
212 vec!["0.0.1".into(), "0.0.2".into(), "0.0.3".into()]
213 ),
214 ("ext2".into(), vec!["0.1.0".into(), "0.2.0".into()])
215 ]
216 .into_iter()
217 .collect()
218 );
219
220 let extensions = db.get_extensions(None, 1, 5).await.unwrap();
221 assert_eq!(
222 extensions,
223 &[
224 ExtensionMetadata {
225 id: "ext2".into(),
226 name: "Extension Two".into(),
227 version: "0.2.0".into(),
228 authors: vec!["marshall".into()],
229 description: "a great extension".into(),
230 repository: "ext2/repo".into(),
231 published_at: t0,
232 download_count: 7
233 },
234 ExtensionMetadata {
235 id: "ext1".into(),
236 name: "Extension One".into(),
237 version: "0.0.3".into(),
238 authors: vec!["max".into(), "marshall".into()],
239 description: "a real good extension".into(),
240 repository: "ext1/repo".into(),
241 published_at: t0,
242 download_count: 5,
243 },
244 ]
245 );
246}