]>
Commit | Line | Data |
---|---|---|
b6be0f39 FE |
1 | use std::path::PathBuf; |
2 | ||
3 | use anyhow::{bail, format_err, Error}; | |
4 | ||
bb0ff2ac FE |
5 | use proxmox_apt::config::APTConfig; |
6 | ||
8ada1785 | 7 | use proxmox_apt::repositories::{ |
f48c12b0 | 8 | check_repositories, get_current_release_codename, standard_repositories, APTRepositoryFile, |
fb51dcf9 | 9 | APTRepositoryHandle, APTRepositoryInfo, APTStandardRepository, DebianCodename, |
8ada1785 | 10 | }; |
b6be0f39 FE |
11 | |
12 | #[test] | |
13 | fn test_parse_write() -> Result<(), Error> { | |
9a51a30f FE |
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> { | |
b6be0f39 | 21 | let test_dir = std::env::current_dir()?.join("tests"); |
9a51a30f | 22 | let read_dir = test_dir.join(read_dir); |
b6be0f39 FE |
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 | } | |
76d3a5ba FE |
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 | ||
87ea23ec FE |
181 | proxmox_apt::config::init(APTConfig::new( |
182 | Some(&test_dir.into_os_string().into_string().unwrap()), | |
183 | None, | |
184 | )); | |
185 | ||
76d3a5ba FE |
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 | ||
fb51dcf9 | 190 | let infos = check_repositories(&vec![file], DebianCodename::Bullseye); |
76d3a5ba FE |
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 | ||
87ea23ec FE |
199 | let origins = [ |
200 | "Debian", "Debian", "Proxmox", "Proxmox", "Proxmox", "Debian", | |
201 | ]; | |
202 | ||
76d3a5ba FE |
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, | |
87ea23ec FE |
208 | property: None, |
209 | kind: "origin".to_string(), | |
210 | message: origins[n].to_string(), | |
76d3a5ba FE |
211 | }); |
212 | } | |
213 | expected_infos.sort(); | |
214 | ||
fb51dcf9 | 215 | let mut infos = check_repositories(&vec![file], DebianCodename::Bullseye); |
76d3a5ba FE |
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, | |
87ea23ec FE |
274 | property: None, |
275 | kind: "origin".to_string(), | |
276 | message: "Debian".to_string(), | |
76d3a5ba FE |
277 | }); |
278 | } | |
279 | expected_infos.sort(); | |
280 | ||
fb51dcf9 | 281 | let mut infos = check_repositories(&vec![file], DebianCodename::Bullseye); |
76d3a5ba FE |
282 | infos.sort(); |
283 | ||
284 | assert_eq!(infos, expected_infos); | |
285 | ||
286 | Ok(()) | |
287 | } | |
bb0ff2ac FE |
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 | ||
8ada1785 FE |
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![ | |
3c4e441d FE |
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), | |
8ada1785 FE |
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 | ||
fb51dcf9 | 340 | let std_repos = standard_repositories(&vec![file], "pve", DebianCodename::Bullseye); |
8ada1785 FE |
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 | ||
fb51dcf9 | 350 | let std_repos = standard_repositories(&file_vec, "pbs", DebianCodename::Bullseye); |
8ada1785 | 351 | |
8ada1785 FE |
352 | assert_eq!(&std_repos, &expected[0..=2]); |
353 | ||
354 | expected[0].status = Some(false); | |
355 | expected[1].status = Some(true); | |
8ada1785 | 356 | |
fb51dcf9 | 357 | let std_repos = standard_repositories(&file_vec, "pve", DebianCodename::Bullseye); |
8ada1785 FE |
358 | |
359 | assert_eq!(std_repos, expected); | |
360 | ||
2a1fb9bf FE |
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 | ||
fb51dcf9 | 371 | let std_repos = standard_repositories(&file_vec, "pve", DebianCodename::Bullseye); |
2a1fb9bf FE |
372 | |
373 | assert_eq!(std_repos, expected); | |
374 | ||
8ada1785 FE |
375 | Ok(()) |
376 | } | |
f48c12b0 FE |
377 | |
378 | #[test] | |
379 | fn test_get_current_release_codename() -> Result<(), Error> { | |
380 | let codename = get_current_release_codename()?; | |
381 | ||
fb51dcf9 | 382 | assert!(codename == DebianCodename::Bullseye); |
f48c12b0 FE |
383 | |
384 | Ok(()) | |
385 | } |