@@ -2348,6 +2348,155 @@ mod tests {
23482348 isolated_config ( std:: env:: temp_dir ( ) . join ( "mega2-config-validate-tests" ) )
23492349 }
23502350
2351+ fn legacy_env_test_child_phase ( test_name : & str ) -> Option < String > {
2352+ match std:: env:: var ( "MEGA2_LEGACY_ENV_TEST_CHILD" ) {
2353+ Err ( std:: env:: VarError :: NotPresent ) => None ,
2354+ Ok ( name) => {
2355+ assert_eq ! ( name, test_name, "child test name" ) ;
2356+ Some ( std:: env:: var ( "MEGA2_LEGACY_ENV_TEST_PHASE" ) . expect ( "child phase" ) )
2357+ }
2358+ Err ( std:: env:: VarError :: NotUnicode ( _) ) => panic ! ( "invalid child test name" ) ,
2359+ }
2360+ }
2361+
2362+ fn run_legacy_env_test_child ( test_name : & str , phase : & str , values : & [ ( & str , & str ) ] ) {
2363+ use std:: {
2364+ io:: Read ,
2365+ process:: { Child , Command , Stdio } ,
2366+ sync:: atomic:: { AtomicBool , Ordering } ,
2367+ thread,
2368+ time:: { Duration , Instant } ,
2369+ } ;
2370+
2371+ const OAUTH_KEYS : [ & str ; 3 ] = [
2372+ "MEGA_OAUTH__CAMPSITE_API_DOMAIN" ,
2373+ "MEGA_OAUTH__TINYSHIP_API_DOMAIN" ,
2374+ "MEGA_OAUTH__API_STORE_BACKEND" ,
2375+ ] ;
2376+ let snapshot = || {
2377+ std:: env:: vars_os ( )
2378+ . filter ( |( key, _) | {
2379+ OAUTH_KEYS
2380+ . iter ( )
2381+ . any ( |name| key. as_os_str ( ) == std:: ffi:: OsStr :: new ( name) )
2382+ || key. to_string_lossy ( ) . starts_with ( "MEGA_MAIL__" )
2383+ } )
2384+ . collect :: < std:: collections:: BTreeMap < _ , _ > > ( )
2385+ } ;
2386+ const OUTPUT_LIMIT : u64 = 1024 * 1024 ;
2387+ struct ChildGuard ( Child ) ;
2388+ impl Drop for ChildGuard {
2389+ fn drop ( & mut self ) {
2390+ let _ = self . 0 . kill ( ) ;
2391+ let _ = self . 0 . wait ( ) ;
2392+ }
2393+ }
2394+
2395+ let before = snapshot ( ) ;
2396+ let mut command = Command :: new ( std:: env:: current_exe ( ) . expect ( "test binary" ) ) ;
2397+ command
2398+ . args ( [
2399+ "--exact" ,
2400+ test_name,
2401+ "--nocapture" ,
2402+ "--test-threads=1" ,
2403+ "--color=never" ,
2404+ ] )
2405+ . env ( "MEGA2_LEGACY_ENV_TEST_CHILD" , test_name)
2406+ . env ( "MEGA2_LEGACY_ENV_TEST_PHASE" , phase)
2407+ . stdin ( Stdio :: null ( ) )
2408+ . stdout ( Stdio :: piped ( ) )
2409+ . stderr ( Stdio :: piped ( ) ) ;
2410+ for key in OAUTH_KEYS {
2411+ command. env_remove ( key) ;
2412+ }
2413+ for key in before. keys ( ) {
2414+ command. env_remove ( key) ;
2415+ }
2416+ for ( key, value) in values {
2417+ command. env ( key, value) ;
2418+ }
2419+ let mut child = ChildGuard (
2420+ command
2421+ . spawn ( )
2422+ . expect ( "spawn isolated legacy environment test" ) ,
2423+ ) ;
2424+ let stdout = child. 0 . stdout . take ( ) . expect ( "child stdout" ) ;
2425+ let stderr = child. 0 . stderr . take ( ) . expect ( "child stderr" ) ;
2426+ let too_large = AtomicBool :: new ( false ) ;
2427+ let deadline = Instant :: now ( ) + Duration :: from_secs ( 20 ) ;
2428+ let read = |stream : Box < dyn Read + Send > | {
2429+ let mut bytes = Vec :: new ( ) ;
2430+ stream
2431+ . take ( OUTPUT_LIMIT + 1 )
2432+ . read_to_end ( & mut bytes)
2433+ . expect ( "read child output" ) ;
2434+ if bytes. len ( ) as u64 > OUTPUT_LIMIT {
2435+ too_large. store ( true , Ordering :: Release ) ;
2436+ }
2437+ bytes
2438+ } ;
2439+ let ( status, stdout, stderr) = thread:: scope ( |scope| {
2440+ let stdout = scope. spawn ( || read ( Box :: new ( stdout) ) ) ;
2441+ let stderr = scope. spawn ( || read ( Box :: new ( stderr) ) ) ;
2442+ let result = loop {
2443+ if too_large. load ( Ordering :: Acquire ) {
2444+ break Err ( "isolated legacy environment test output limit exceeded" ) ;
2445+ }
2446+ if Instant :: now ( ) >= deadline {
2447+ break Err ( "isolated legacy environment test exceeded 20 seconds" ) ;
2448+ }
2449+ if snapshot ( ) != before {
2450+ break Err (
2451+ "isolated legacy environment test changed parent legacy environment" ,
2452+ ) ;
2453+ }
2454+ match child. 0 . try_wait ( ) {
2455+ Ok ( Some ( status) ) => break Ok ( status) ,
2456+ Ok ( None ) => thread:: sleep ( Duration :: from_millis ( 5 ) ) ,
2457+ Err ( _) => break Err ( "could not wait for isolated legacy environment test" ) ,
2458+ }
2459+ } ;
2460+ // Close pipes before joining readers, including every failure path.
2461+ if result. is_err ( ) {
2462+ let _ = child. 0 . kill ( ) ;
2463+ let _ = child. 0 . wait ( ) ;
2464+ }
2465+ (
2466+ result,
2467+ stdout. join ( ) . expect ( "stdout reader" ) ,
2468+ stderr. join ( ) . expect ( "stderr reader" ) ,
2469+ )
2470+ } ) ;
2471+ assert ! (
2472+ stdout. len( ) as u64 <= OUTPUT_LIMIT && stderr. len( ) as u64 <= OUTPUT_LIMIT ,
2473+ "child output limit"
2474+ ) ;
2475+ let stdout = String :: from_utf8_lossy ( & stdout) ;
2476+ let stderr = String :: from_utf8_lossy ( & stderr) ;
2477+ assert ! (
2478+ status
2479+ . expect( "isolated legacy environment test completion" )
2480+ . success( ) ,
2481+ "{stdout}\n {stderr}"
2482+ ) ;
2483+ assert_eq ! (
2484+ stdout
2485+ . lines( )
2486+ . filter( |line| * line == format!( "test {test_name} ... ok" ) )
2487+ . count( ) ,
2488+ 1 ,
2489+ "{stdout}"
2490+ ) ;
2491+ assert ! (
2492+ stdout
2493+ . lines( )
2494+ . any( |line| line. starts_with( "test result: ok. 1 passed; 0 failed; 0 ignored;" ) ) ,
2495+ "{stdout}"
2496+ ) ;
2497+ assert ! ( snapshot( ) == before, "parent legacy environment changed" ) ;
2498+ }
2499+
23512500 fn assert_views_validation_error ( config : Config , field : & str ) {
23522501 let err = config
23532502 . validate ( )
@@ -2951,15 +3100,20 @@ mod tests {
29513100
29523101 #[ test]
29533102 fn config_validate_rejects_legacy_oauth_environment_variables ( ) {
2954- use crate :: config:: testing:: { EnvVarGuard , env_lock} ;
2955-
2956- let lock = env_lock ( ) ;
3103+ const TEST_NAME : & str =
3104+ "config::validate::tests::config_validate_rejects_legacy_oauth_environment_variables" ;
3105+ match legacy_env_test_child_phase ( TEST_NAME ) {
3106+ None => {
3107+ run_legacy_env_test_child (
3108+ TEST_NAME ,
3109+ "oauth" ,
3110+ & [ ( "MEGA_OAUTH__CAMPSITE_API_DOMAIN" , "http://legacy.example" ) ] ,
3111+ ) ;
3112+ return ;
3113+ }
3114+ Some ( phase) => assert_eq ! ( phase, "oauth" , "child phase" ) ,
3115+ }
29573116 let config = valid_config ( ) ;
2958- let _var = EnvVarGuard :: set (
2959- & lock,
2960- "MEGA_OAUTH__CAMPSITE_API_DOMAIN" ,
2961- "http://legacy.example" ,
2962- ) ;
29633117 let err = config
29643118 . validate ( )
29653119 . expect_err ( "legacy MEGA_OAUTH__CAMPSITE_API_DOMAIN should fail validate" ) ;
@@ -2971,11 +3125,16 @@ mod tests {
29713125
29723126 #[ test]
29733127 fn config_validate_rejects_legacy_mail_environment_variables ( ) {
2974- use crate :: config:: testing:: { EnvVarGuard , env_lock} ;
2975-
2976- let lock = env_lock ( ) ;
3128+ const TEST_NAME : & str =
3129+ "config::validate::tests::config_validate_rejects_legacy_mail_environment_variables" ;
3130+ match legacy_env_test_child_phase ( TEST_NAME ) {
3131+ None => {
3132+ run_legacy_env_test_child ( TEST_NAME , "mail" , & [ ( "MEGA_MAIL__ENABLED" , "true" ) ] ) ;
3133+ return ;
3134+ }
3135+ Some ( phase) => assert_eq ! ( phase, "mail" , "child phase" ) ,
3136+ }
29773137 let config = valid_config ( ) ;
2978- let _var = EnvVarGuard :: set ( & lock, "MEGA_MAIL__ENABLED" , "true" ) ;
29793138 let err = config
29803139 . validate ( )
29813140 . expect_err ( "legacy MEGA_MAIL__ENABLED should fail validate" ) ;
0 commit comments