]> git.proxmox.com Git - proxmox-apt.git/blob - tests/repositories.rs
clippy fixes
[proxmox-apt.git] / tests / repositories.rs
1 use std::path::PathBuf;
2
3 use anyhow::{bail, format_err, Error};
4
5 use proxmox_apt::config::APTConfig;
6
7 use proxmox_apt::repositories::{
8 check_repositories, get_current_release_codename, standard_repositories, APTRepositoryFile,
9 APTRepositoryHandle, APTRepositoryInfo, APTStandardRepository, DebianCodename,
10 };
11
12 #[test]
13 fn test_parse_write() -> Result<(), Error> {
14 test_parse_write_dir("sources.list.d")?;
15 test_parse_write_dir("sources.list.d.expected")?; // check if it's idempotent
16
17 Ok(())
18 }
19
20 fn test_parse_write_dir(read_dir: &str) -> Result<(), Error> {
21 let test_dir = std::env::current_dir()?.join("tests");
22 let read_dir = test_dir.join(read_dir);
23 let write_dir = test_dir.join("sources.list.d.actual");
24 let expected_dir = test_dir.join("sources.list.d.expected");
25
26 if write_dir.is_dir() {
27 std::fs::remove_dir_all(&write_dir)
28 .map_err(|err| format_err!("unable to remove dir {:?} - {}", write_dir, err))?;
29 }
30
31 std::fs::create_dir_all(&write_dir)
32 .map_err(|err| format_err!("unable to create dir {:?} - {}", write_dir, err))?;
33
34 let mut files = vec![];
35 let mut errors = vec![];
36
37 for entry in std::fs::read_dir(read_dir)? {
38 let path = entry?.path();
39
40 match APTRepositoryFile::new(&path)? {
41 Some(mut file) => match file.parse() {
42 Ok(()) => files.push(file),
43 Err(err) => errors.push(err),
44 },
45 None => bail!("unexpected None for '{:?}'", path),
46 }
47 }
48
49 assert!(errors.is_empty());
50
51 for file in files.iter_mut() {
52 let path = match &file.path {
53 Some(path) => path,
54 None => continue,
55 };
56 let path = PathBuf::from(path);
57 let new_path = write_dir.join(path.file_name().unwrap());
58 file.path = Some(new_path.into_os_string().into_string().unwrap());
59 file.digest = None;
60 file.write()?;
61 }
62
63 let mut expected_count = 0;
64
65 for entry in std::fs::read_dir(expected_dir)? {
66 expected_count += 1;
67
68 let expected_path = entry?.path();
69 let actual_path = write_dir.join(expected_path.file_name().unwrap());
70
71 let expected_contents = std::fs::read(&expected_path)
72 .map_err(|err| format_err!("unable to read {:?} - {}", expected_path, err))?;
73
74 let actual_contents = std::fs::read(&actual_path)
75 .map_err(|err| format_err!("unable to read {:?} - {}", actual_path, err))?;
76
77 assert_eq!(
78 expected_contents, actual_contents,
79 "Use\n\ndiff {:?} {:?}\n\nif you're not fluent in byte decimals",
80 expected_path, actual_path
81 );
82 }
83
84 let actual_count = std::fs::read_dir(write_dir)?.count();
85
86 assert_eq!(expected_count, actual_count);
87
88 Ok(())
89 }
90
91 #[test]
92 fn test_digest() -> Result<(), Error> {
93 let test_dir = std::env::current_dir()?.join("tests");
94 let read_dir = test_dir.join("sources.list.d");
95 let write_dir = test_dir.join("sources.list.d.digest");
96
97 if write_dir.is_dir() {
98 std::fs::remove_dir_all(&write_dir)
99 .map_err(|err| format_err!("unable to remove dir {:?} - {}", write_dir, err))?;
100 }
101
102 std::fs::create_dir_all(&write_dir)
103 .map_err(|err| format_err!("unable to create dir {:?} - {}", write_dir, err))?;
104
105 let path = read_dir.join("standard.list");
106
107 let mut file = APTRepositoryFile::new(&path)?.unwrap();
108 file.parse()?;
109
110 let new_path = write_dir.join(path.file_name().unwrap());
111 file.path = Some(new_path.clone().into_os_string().into_string().unwrap());
112
113 let old_digest = file.digest.unwrap();
114
115 // file does not exist yet...
116 assert!(file.read_with_digest().is_err());
117 assert!(file.write().is_err());
118
119 // ...but it should work if there's no digest
120 file.digest = None;
121 file.write()?;
122
123 // overwrite with old contents...
124 std::fs::copy(path, new_path)?;
125
126 // modify the repo
127 let mut repo = file.repositories.first_mut().unwrap();
128 repo.enabled = !repo.enabled;
129
130 // ...then it should work
131 file.digest = Some(old_digest);
132 file.write()?;
133
134 // expect a different digest, because the repo was modified
135 let (_, new_digest) = file.read_with_digest()?;
136 assert_ne!(old_digest, new_digest);
137
138 assert!(file.write().is_err());
139
140 Ok(())
141 }
142
143 #[test]
144 fn test_empty_write() -> Result<(), Error> {
145 let test_dir = std::env::current_dir()?.join("tests");
146 let read_dir = test_dir.join("sources.list.d");
147 let write_dir = test_dir.join("sources.list.d.remove");
148
149 if write_dir.is_dir() {
150 std::fs::remove_dir_all(&write_dir)
151 .map_err(|err| format_err!("unable to remove dir {:?} - {}", write_dir, err))?;
152 }
153
154 std::fs::create_dir_all(&write_dir)
155 .map_err(|err| format_err!("unable to create dir {:?} - {}", write_dir, err))?;
156
157 let path = read_dir.join("standard.list");
158
159 let mut file = APTRepositoryFile::new(&path)?.unwrap();
160 file.parse()?;
161
162 let new_path = write_dir.join(path.file_name().unwrap());
163 file.path = Some(new_path.into_os_string().into_string().unwrap());
164
165 file.digest = None;
166
167 file.write()?;
168
169 assert!(file.exists());
170
171 file.repositories.clear();
172
173 file.write()?;
174
175 assert!(!file.exists());
176
177 Ok(())
178 }
179
180 #[test]
181 fn test_check_repositories() -> Result<(), Error> {
182 let test_dir = std::env::current_dir()?.join("tests");
183 let read_dir = test_dir.join("sources.list.d");
184
185 proxmox_apt::config::init(APTConfig::new(
186 Some(&test_dir.into_os_string().into_string().unwrap()),
187 None,
188 ));
189
190 let absolute_suite_list = read_dir.join("absolute_suite.list");
191 let mut file = APTRepositoryFile::new(&absolute_suite_list)?.unwrap();
192 file.parse()?;
193
194 let infos = check_repositories(&[file], DebianCodename::Bullseye);
195
196 assert!(infos.is_empty());
197 let pve_list = read_dir.join("pve.list");
198 let mut file = APTRepositoryFile::new(&pve_list)?.unwrap();
199 file.parse()?;
200
201 let path_string = pve_list.into_os_string().into_string().unwrap();
202
203 let origins = [
204 "Debian", "Debian", "Proxmox", "Proxmox", "Proxmox", "Debian",
205 ];
206
207 let mut expected_infos = vec![];
208 for (n, origin) in origins.into_iter().enumerate() {
209 expected_infos.push(APTRepositoryInfo {
210 path: path_string.clone(),
211 index: n,
212 property: None,
213 kind: "origin".to_string(),
214 message: origin.to_string(),
215 });
216 }
217 expected_infos.sort();
218
219 let mut infos = check_repositories(&[file], DebianCodename::Bullseye);
220 infos.sort();
221
222 assert_eq!(infos, expected_infos);
223
224 let bad_sources = read_dir.join("bad.sources");
225 let mut file = APTRepositoryFile::new(&bad_sources)?.unwrap();
226 file.parse()?;
227
228 let path_string = bad_sources.into_os_string().into_string().unwrap();
229
230 let mut expected_infos = vec![
231 APTRepositoryInfo {
232 path: path_string.clone(),
233 index: 0,
234 property: Some("Suites".to_string()),
235 kind: "warning".to_string(),
236 message: "suite 'sid' should not be used in production!".to_string(),
237 },
238 APTRepositoryInfo {
239 path: path_string.clone(),
240 index: 1,
241 property: Some("Suites".to_string()),
242 kind: "warning".to_string(),
243 message: "old suite 'lenny' configured!".to_string(),
244 },
245 APTRepositoryInfo {
246 path: path_string.clone(),
247 index: 2,
248 property: Some("Suites".to_string()),
249 kind: "warning".to_string(),
250 message: "old suite 'stretch' configured!".to_string(),
251 },
252 APTRepositoryInfo {
253 path: path_string.clone(),
254 index: 3,
255 property: Some("Suites".to_string()),
256 kind: "warning".to_string(),
257 message: "use the name of the stable distribution instead of 'stable'!".to_string(),
258 },
259 APTRepositoryInfo {
260 path: path_string.clone(),
261 index: 4,
262 property: Some("Suites".to_string()),
263 kind: "ignore-pre-upgrade-warning".to_string(),
264 message: "suite 'bookworm' should not be used in production!".to_string(),
265 },
266 APTRepositoryInfo {
267 path: path_string.clone(),
268 index: 5,
269 property: Some("Suites".to_string()),
270 kind: "warning".to_string(),
271 message: "suite 'testing' should not be used in production!".to_string(),
272 },
273 ];
274 for n in 0..=5 {
275 expected_infos.push(APTRepositoryInfo {
276 path: path_string.clone(),
277 index: n,
278 property: None,
279 kind: "origin".to_string(),
280 message: "Debian".to_string(),
281 });
282 }
283 expected_infos.sort();
284
285 let mut infos = check_repositories(&[file], DebianCodename::Bullseye);
286 infos.sort();
287
288 assert_eq!(infos, expected_infos);
289
290 let bad_security = read_dir.join("bad-security.list");
291 let mut file = APTRepositoryFile::new(&bad_security)?.unwrap();
292 file.parse()?;
293
294 let path_string = bad_security.into_os_string().into_string().unwrap();
295
296 let mut expected_infos = vec![];
297 for n in 0..=1 {
298 expected_infos.push(APTRepositoryInfo {
299 path: path_string.clone(),
300 index: n,
301 property: Some("Suites".to_string()),
302 kind: "warning".to_string(),
303 message: "expected suite 'bullseye-security'".to_string(),
304 });
305 }
306 for n in 0..=1 {
307 expected_infos.push(APTRepositoryInfo {
308 path: path_string.clone(),
309 index: n,
310 property: None,
311 kind: "origin".to_string(),
312 message: "Debian".to_string(),
313 });
314 }
315 expected_infos.sort();
316
317 let mut infos = check_repositories(&[file], DebianCodename::Bullseye);
318 infos.sort();
319
320 assert_eq!(infos, expected_infos);
321 Ok(())
322 }
323
324 #[test]
325 fn test_get_cached_origin() -> Result<(), Error> {
326 let test_dir = std::env::current_dir()?.join("tests");
327 let read_dir = test_dir.join("sources.list.d");
328
329 proxmox_apt::config::init(APTConfig::new(
330 Some(&test_dir.into_os_string().into_string().unwrap()),
331 None,
332 ));
333
334 let pve_list = read_dir.join("pve.list");
335 let mut file = APTRepositoryFile::new(&pve_list)?.unwrap();
336 file.parse()?;
337
338 let origins = [
339 Some("Debian".to_string()),
340 Some("Debian".to_string()),
341 Some("Proxmox".to_string()),
342 None, // no cache file exists
343 None, // no cache file exists
344 Some("Debian".to_string()),
345 ];
346
347 assert_eq!(file.repositories.len(), origins.len());
348
349 for (n, repo) in file.repositories.iter().enumerate() {
350 assert_eq!(repo.get_cached_origin()?, origins[n]);
351 }
352
353 Ok(())
354 }
355
356 #[test]
357 fn test_standard_repositories() -> Result<(), Error> {
358 let test_dir = std::env::current_dir()?.join("tests");
359 let read_dir = test_dir.join("sources.list.d");
360
361 let mut expected = vec![
362 APTStandardRepository::from(APTRepositoryHandle::Enterprise),
363 APTStandardRepository::from(APTRepositoryHandle::NoSubscription),
364 APTStandardRepository::from(APTRepositoryHandle::Test),
365 APTStandardRepository::from(APTRepositoryHandle::CephQuincy),
366 APTStandardRepository::from(APTRepositoryHandle::CephQuincyTest),
367 APTStandardRepository::from(APTRepositoryHandle::CephPacific),
368 APTStandardRepository::from(APTRepositoryHandle::CephPacificTest),
369 APTStandardRepository::from(APTRepositoryHandle::CephOctopus),
370 APTStandardRepository::from(APTRepositoryHandle::CephOctopusTest),
371 ];
372
373 let absolute_suite_list = read_dir.join("absolute_suite.list");
374 let mut file = APTRepositoryFile::new(&absolute_suite_list)?.unwrap();
375 file.parse()?;
376
377 let std_repos = standard_repositories(&[file], "pve", DebianCodename::Bullseye);
378
379 assert_eq!(std_repos, expected);
380
381 let pve_list = read_dir.join("pve.list");
382 let mut file = APTRepositoryFile::new(&pve_list)?.unwrap();
383 file.parse()?;
384
385 let file_vec = vec![file];
386
387 let std_repos = standard_repositories(&file_vec, "pbs", DebianCodename::Bullseye);
388
389 assert_eq!(&std_repos, &expected[0..=2]);
390
391 expected[0].status = Some(false);
392 expected[1].status = Some(true);
393
394 let std_repos = standard_repositories(&file_vec, "pve", DebianCodename::Bullseye);
395
396 assert_eq!(std_repos, expected);
397
398 let pve_alt_list = read_dir.join("pve-alt.list");
399 let mut file = APTRepositoryFile::new(&pve_alt_list)?.unwrap();
400 file.parse()?;
401
402 let file_vec = vec![file];
403
404 expected[0].status = Some(true);
405 expected[1].status = Some(true);
406 expected[2].status = Some(false);
407
408 let std_repos = standard_repositories(&file_vec, "pve", DebianCodename::Bullseye);
409
410 assert_eq!(std_repos, expected);
411
412 Ok(())
413 }
414
415 #[test]
416 fn test_get_current_release_codename() -> Result<(), Error> {
417 let codename = get_current_release_codename()?;
418
419 assert!(codename == DebianCodename::Bullseye);
420
421 Ok(())
422 }