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