2021-06-23 16:38:54 +03:00
use std ::path ::PathBuf ;
use anyhow ::{ bail , format_err , Error } ;
2021-06-30 13:20:16 +03:00
use proxmox_apt ::config ::APTConfig ;
2021-06-23 16:38:57 +03:00
use proxmox_apt ::repositories ::{
2021-07-29 15:25:48 +03:00
check_repositories , get_current_release_codename , standard_repositories , APTRepositoryFile ,
2021-07-29 15:25:52 +03:00
APTRepositoryHandle , APTRepositoryInfo , APTStandardRepository , DebianCodename ,
2021-06-23 16:38:57 +03:00
} ;
2021-06-23 16:38:54 +03:00
#[ test ]
fn test_parse_write ( ) -> Result < ( ) , Error > {
2021-07-02 12:31:24 +03:00
test_parse_write_dir ( " sources.list.d " ) ? ;
test_parse_write_dir ( " sources.list.d.expected " ) ? ; // check if it's idempotent
Ok ( ( ) )
}
fn test_parse_write_dir ( read_dir : & str ) -> Result < ( ) , Error > {
2021-06-23 16:38:54 +03:00
let test_dir = std ::env ::current_dir ( ) ? . join ( " tests " ) ;
2023-06-02 11:48:22 +03:00
let tmp_dir = PathBuf ::from ( env! ( " CARGO_TARGET_TMPDIR " ) . to_string ( ) ) ;
2021-07-02 12:31:24 +03:00
let read_dir = test_dir . join ( read_dir ) ;
2023-06-02 11:48:22 +03:00
let write_dir = tmp_dir . join ( " sources.list.d.actual " ) ;
2021-06-23 16:38:54 +03:00
let expected_dir = test_dir . join ( " sources.list.d.expected " ) ;
std ::fs ::create_dir_all ( & write_dir )
. map_err ( | err | format_err! ( " unable to create dir {:?} - {} " , write_dir , err ) ) ? ;
let mut files = vec! [ ] ;
let mut errors = vec! [ ] ;
for entry in std ::fs ::read_dir ( read_dir ) ? {
let path = entry ? . path ( ) ;
match APTRepositoryFile ::new ( & path ) ? {
Some ( mut file ) = > match file . parse ( ) {
Ok ( ( ) ) = > files . push ( file ) ,
Err ( err ) = > errors . push ( err ) ,
} ,
None = > bail! ( " unexpected None for '{:?}' " , path ) ,
}
}
assert! ( errors . is_empty ( ) ) ;
for file in files . iter_mut ( ) {
2022-04-05 16:07:43 +03:00
let path = match & file . path {
Some ( path ) = > path ,
None = > continue ,
} ;
let path = PathBuf ::from ( path ) ;
2021-06-23 16:38:54 +03:00
let new_path = write_dir . join ( path . file_name ( ) . unwrap ( ) ) ;
2022-04-05 16:07:43 +03:00
file . path = Some ( new_path . into_os_string ( ) . into_string ( ) . unwrap ( ) ) ;
2021-06-23 16:38:54 +03:00
file . digest = None ;
file . write ( ) ? ;
}
let mut expected_count = 0 ;
for entry in std ::fs ::read_dir ( expected_dir ) ? {
expected_count + = 1 ;
let expected_path = entry ? . path ( ) ;
2023-06-02 11:48:22 +03:00
2021-06-23 16:38:54 +03:00
let actual_path = write_dir . join ( expected_path . file_name ( ) . unwrap ( ) ) ;
let expected_contents = std ::fs ::read ( & expected_path )
. map_err ( | err | format_err! ( " unable to read {:?} - {} " , expected_path , err ) ) ? ;
let actual_contents = std ::fs ::read ( & actual_path )
. map_err ( | err | format_err! ( " unable to read {:?} - {} " , actual_path , err ) ) ? ;
assert_eq! (
expected_contents , actual_contents ,
" Use \n \n diff {:?} {:?} \n \n if you're not fluent in byte decimals " ,
expected_path , actual_path
) ;
}
let actual_count = std ::fs ::read_dir ( write_dir ) ? . count ( ) ;
assert_eq! ( expected_count , actual_count ) ;
Ok ( ( ) )
}
#[ test ]
fn test_digest ( ) -> Result < ( ) , Error > {
let test_dir = std ::env ::current_dir ( ) ? . join ( " tests " ) ;
2023-06-02 11:48:22 +03:00
let tmp_dir = PathBuf ::from ( env! ( " CARGO_TARGET_TMPDIR " ) . to_string ( ) ) ;
2021-06-23 16:38:54 +03:00
let read_dir = test_dir . join ( " sources.list.d " ) ;
2023-06-02 11:48:22 +03:00
let write_dir = tmp_dir . join ( " sources.list.d.digest " ) ;
2021-06-23 16:38:54 +03:00
std ::fs ::create_dir_all ( & write_dir )
. map_err ( | err | format_err! ( " unable to create dir {:?} - {} " , write_dir , err ) ) ? ;
let path = read_dir . join ( " standard.list " ) ;
let mut file = APTRepositoryFile ::new ( & path ) ? . unwrap ( ) ;
file . parse ( ) ? ;
let new_path = write_dir . join ( path . file_name ( ) . unwrap ( ) ) ;
2022-04-05 16:07:43 +03:00
file . path = Some ( new_path . clone ( ) . into_os_string ( ) . into_string ( ) . unwrap ( ) ) ;
2021-06-23 16:38:54 +03:00
let old_digest = file . digest . unwrap ( ) ;
// file does not exist yet...
assert! ( file . read_with_digest ( ) . is_err ( ) ) ;
assert! ( file . write ( ) . is_err ( ) ) ;
// ...but it should work if there's no digest
file . digest = None ;
file . write ( ) ? ;
// overwrite with old contents...
std ::fs ::copy ( path , new_path ) ? ;
// modify the repo
let mut repo = file . repositories . first_mut ( ) . unwrap ( ) ;
repo . enabled = ! repo . enabled ;
// ...then it should work
file . digest = Some ( old_digest ) ;
file . write ( ) ? ;
// expect a different digest, because the repo was modified
let ( _ , new_digest ) = file . read_with_digest ( ) ? ;
assert_ne! ( old_digest , new_digest ) ;
assert! ( file . write ( ) . is_err ( ) ) ;
Ok ( ( ) )
}
#[ test ]
fn test_empty_write ( ) -> Result < ( ) , Error > {
let test_dir = std ::env ::current_dir ( ) ? . join ( " tests " ) ;
let read_dir = test_dir . join ( " sources.list.d " ) ;
let write_dir = test_dir . join ( " sources.list.d.remove " ) ;
if write_dir . is_dir ( ) {
std ::fs ::remove_dir_all ( & write_dir )
. map_err ( | err | format_err! ( " unable to remove dir {:?} - {} " , write_dir , err ) ) ? ;
}
std ::fs ::create_dir_all ( & write_dir )
. map_err ( | err | format_err! ( " unable to create dir {:?} - {} " , write_dir , err ) ) ? ;
let path = read_dir . join ( " standard.list " ) ;
let mut file = APTRepositoryFile ::new ( & path ) ? . unwrap ( ) ;
file . parse ( ) ? ;
let new_path = write_dir . join ( path . file_name ( ) . unwrap ( ) ) ;
2022-10-12 11:41:42 +03:00
file . path = Some ( new_path . into_os_string ( ) . into_string ( ) . unwrap ( ) ) ;
2021-06-23 16:38:54 +03:00
file . digest = None ;
file . write ( ) ? ;
assert! ( file . exists ( ) ) ;
file . repositories . clear ( ) ;
file . write ( ) ? ;
assert! ( ! file . exists ( ) ) ;
Ok ( ( ) )
}
2021-06-23 16:38:56 +03:00
#[ test ]
fn test_check_repositories ( ) -> Result < ( ) , Error > {
let test_dir = std ::env ::current_dir ( ) ? . join ( " tests " ) ;
let read_dir = test_dir . join ( " sources.list.d " ) ;
2021-06-30 13:20:17 +03:00
proxmox_apt ::config ::init ( APTConfig ::new (
Some ( & test_dir . into_os_string ( ) . into_string ( ) . unwrap ( ) ) ,
None ,
) ) ;
2021-06-23 16:38:56 +03:00
let absolute_suite_list = read_dir . join ( " absolute_suite.list " ) ;
let mut file = APTRepositoryFile ::new ( & absolute_suite_list ) ? . unwrap ( ) ;
file . parse ( ) ? ;
2022-10-12 11:41:42 +03:00
let infos = check_repositories ( & [ file ] , DebianCodename ::Bullseye ) ;
2021-06-23 16:38:56 +03:00
2022-10-12 11:41:42 +03:00
assert! ( infos . is_empty ( ) ) ;
2021-06-23 16:38:56 +03:00
let pve_list = read_dir . join ( " pve.list " ) ;
let mut file = APTRepositoryFile ::new ( & pve_list ) ? . unwrap ( ) ;
file . parse ( ) ? ;
let path_string = pve_list . into_os_string ( ) . into_string ( ) . unwrap ( ) ;
2021-06-30 13:20:17 +03:00
let origins = [
" Debian " , " Debian " , " Proxmox " , " Proxmox " , " Proxmox " , " Debian " ,
] ;
2021-06-23 16:38:56 +03:00
let mut expected_infos = vec! [ ] ;
2022-10-12 11:41:42 +03:00
for ( n , origin ) in origins . into_iter ( ) . enumerate ( ) {
2021-06-23 16:38:56 +03:00
expected_infos . push ( APTRepositoryInfo {
path : path_string . clone ( ) ,
index : n ,
2021-06-30 13:20:17 +03:00
property : None ,
kind : " origin " . to_string ( ) ,
2022-10-12 11:41:42 +03:00
message : origin . to_string ( ) ,
2021-06-23 16:38:56 +03:00
} ) ;
}
expected_infos . sort ( ) ;
2022-10-12 11:41:42 +03:00
let mut infos = check_repositories ( & [ file ] , DebianCodename ::Bullseye ) ;
2021-06-23 16:38:56 +03:00
infos . sort ( ) ;
assert_eq! ( infos , expected_infos ) ;
let bad_sources = read_dir . join ( " bad.sources " ) ;
let mut file = APTRepositoryFile ::new ( & bad_sources ) ? . unwrap ( ) ;
file . parse ( ) ? ;
let path_string = bad_sources . into_os_string ( ) . into_string ( ) . unwrap ( ) ;
let mut expected_infos = vec! [
APTRepositoryInfo {
path : path_string . clone ( ) ,
index : 0 ,
property : Some ( " Suites " . to_string ( ) ) ,
kind : " warning " . to_string ( ) ,
message : " suite 'sid' should not be used in production! " . to_string ( ) ,
} ,
APTRepositoryInfo {
path : path_string . clone ( ) ,
index : 1 ,
property : Some ( " Suites " . to_string ( ) ) ,
kind : " warning " . to_string ( ) ,
message : " old suite 'lenny' configured! " . to_string ( ) ,
} ,
APTRepositoryInfo {
path : path_string . clone ( ) ,
index : 2 ,
property : Some ( " Suites " . to_string ( ) ) ,
kind : " warning " . to_string ( ) ,
message : " old suite 'stretch' configured! " . to_string ( ) ,
} ,
APTRepositoryInfo {
path : path_string . clone ( ) ,
index : 3 ,
property : Some ( " Suites " . to_string ( ) ) ,
kind : " warning " . to_string ( ) ,
message : " use the name of the stable distribution instead of 'stable'! " . to_string ( ) ,
} ,
APTRepositoryInfo {
path : path_string . clone ( ) ,
index : 4 ,
property : Some ( " Suites " . to_string ( ) ) ,
kind : " ignore-pre-upgrade-warning " . to_string ( ) ,
message : " suite 'bookworm' should not be used in production! " . to_string ( ) ,
} ,
APTRepositoryInfo {
path : path_string . clone ( ) ,
index : 5 ,
property : Some ( " Suites " . to_string ( ) ) ,
kind : " warning " . to_string ( ) ,
message : " suite 'testing' should not be used in production! " . to_string ( ) ,
} ,
] ;
for n in 0 ..= 5 {
expected_infos . push ( APTRepositoryInfo {
path : path_string . clone ( ) ,
index : n ,
2021-06-30 13:20:17 +03:00
property : None ,
kind : " origin " . to_string ( ) ,
message : " Debian " . to_string ( ) ,
2021-06-23 16:38:56 +03:00
} ) ;
}
expected_infos . sort ( ) ;
2022-10-12 11:41:42 +03:00
let mut infos = check_repositories ( & [ file ] , DebianCodename ::Bullseye ) ;
2021-06-23 16:38:56 +03:00
infos . sort ( ) ;
assert_eq! ( infos , expected_infos ) ;
2022-01-18 15:48:22 +03:00
let bad_security = read_dir . join ( " bad-security.list " ) ;
let mut file = APTRepositoryFile ::new ( & bad_security ) ? . unwrap ( ) ;
file . parse ( ) ? ;
let path_string = bad_security . into_os_string ( ) . into_string ( ) . unwrap ( ) ;
let mut expected_infos = vec! [ ] ;
for n in 0 ..= 1 {
expected_infos . push ( APTRepositoryInfo {
path : path_string . clone ( ) ,
index : n ,
property : Some ( " Suites " . to_string ( ) ) ,
kind : " warning " . to_string ( ) ,
message : " expected suite 'bullseye-security' " . to_string ( ) ,
} ) ;
}
for n in 0 ..= 1 {
expected_infos . push ( APTRepositoryInfo {
path : path_string . clone ( ) ,
index : n ,
property : None ,
kind : " origin " . to_string ( ) ,
message : " Debian " . to_string ( ) ,
} ) ;
}
expected_infos . sort ( ) ;
2022-10-12 11:41:42 +03:00
let mut infos = check_repositories ( & [ file ] , DebianCodename ::Bullseye ) ;
2022-01-18 15:48:22 +03:00
infos . sort ( ) ;
assert_eq! ( infos , expected_infos ) ;
2021-06-23 16:38:56 +03:00
Ok ( ( ) )
}
2021-06-30 13:20:16 +03:00
#[ test ]
fn test_get_cached_origin ( ) -> Result < ( ) , Error > {
let test_dir = std ::env ::current_dir ( ) ? . join ( " tests " ) ;
let read_dir = test_dir . join ( " sources.list.d " ) ;
proxmox_apt ::config ::init ( APTConfig ::new (
Some ( & test_dir . into_os_string ( ) . into_string ( ) . unwrap ( ) ) ,
None ,
) ) ;
let pve_list = read_dir . join ( " pve.list " ) ;
let mut file = APTRepositoryFile ::new ( & pve_list ) ? . unwrap ( ) ;
file . parse ( ) ? ;
let origins = [
Some ( " Debian " . to_string ( ) ) ,
Some ( " Debian " . to_string ( ) ) ,
Some ( " Proxmox " . to_string ( ) ) ,
None , // no cache file exists
None , // no cache file exists
Some ( " Debian " . to_string ( ) ) ,
] ;
assert_eq! ( file . repositories . len ( ) , origins . len ( ) ) ;
for ( n , repo ) in file . repositories . iter ( ) . enumerate ( ) {
assert_eq! ( repo . get_cached_origin ( ) ? , origins [ n ] ) ;
}
Ok ( ( ) )
}
2021-06-23 16:38:57 +03:00
#[ test ]
fn test_standard_repositories ( ) -> Result < ( ) , Error > {
let test_dir = std ::env ::current_dir ( ) ? . join ( " tests " ) ;
let read_dir = test_dir . join ( " sources.list.d " ) ;
let mut expected = vec! [
2021-06-30 18:07:53 +03:00
APTStandardRepository ::from ( APTRepositoryHandle ::Enterprise ) ,
APTStandardRepository ::from ( APTRepositoryHandle ::NoSubscription ) ,
APTStandardRepository ::from ( APTRepositoryHandle ::Test ) ,
2023-06-02 11:48:21 +03:00
APTStandardRepository ::from ( APTRepositoryHandle ::CephQuincyEnterprise ) ,
APTStandardRepository ::from ( APTRepositoryHandle ::CephQuincyNoSubscription ) ,
2022-08-02 15:59:27 +03:00
APTStandardRepository ::from ( APTRepositoryHandle ::CephQuincyTest ) ,
2021-06-23 16:38:57 +03:00
] ;
let absolute_suite_list = read_dir . join ( " absolute_suite.list " ) ;
let mut file = APTRepositoryFile ::new ( & absolute_suite_list ) ? . unwrap ( ) ;
file . parse ( ) ? ;
2022-10-12 11:41:42 +03:00
let std_repos = standard_repositories ( & [ file ] , " pve " , DebianCodename ::Bullseye ) ;
2021-06-23 16:38:57 +03:00
assert_eq! ( std_repos , expected ) ;
let pve_list = read_dir . join ( " pve.list " ) ;
let mut file = APTRepositoryFile ::new ( & pve_list ) ? . unwrap ( ) ;
file . parse ( ) ? ;
let file_vec = vec! [ file ] ;
2021-07-29 15:25:52 +03:00
let std_repos = standard_repositories ( & file_vec , " pbs " , DebianCodename ::Bullseye ) ;
2021-06-23 16:38:57 +03:00
assert_eq! ( & std_repos , & expected [ 0 ..= 2 ] ) ;
expected [ 0 ] . status = Some ( false ) ;
expected [ 1 ] . status = Some ( true ) ;
2021-07-29 15:25:52 +03:00
let std_repos = standard_repositories ( & file_vec , " pve " , DebianCodename ::Bullseye ) ;
2021-06-23 16:38:57 +03:00
assert_eq! ( std_repos , expected ) ;
2021-07-16 15:36:02 +03:00
let pve_alt_list = read_dir . join ( " pve-alt.list " ) ;
let mut file = APTRepositoryFile ::new ( & pve_alt_list ) ? . unwrap ( ) ;
file . parse ( ) ? ;
let file_vec = vec! [ file ] ;
expected [ 0 ] . status = Some ( true ) ;
expected [ 1 ] . status = Some ( true ) ;
expected [ 2 ] . status = Some ( false ) ;
2021-07-29 15:25:52 +03:00
let std_repos = standard_repositories ( & file_vec , " pve " , DebianCodename ::Bullseye ) ;
2021-07-16 15:36:02 +03:00
assert_eq! ( std_repos , expected ) ;
2021-06-23 16:38:57 +03:00
Ok ( ( ) )
}
2021-07-29 15:25:48 +03:00
#[ test ]
fn test_get_current_release_codename ( ) -> Result < ( ) , Error > {
let codename = get_current_release_codename ( ) ? ;
2023-05-24 10:50:24 +03:00
assert! ( codename = = DebianCodename ::Bookworm ) ;
2021-07-29 15:25:48 +03:00
Ok ( ( ) )
}