99
1010use std:: time:: Duration ;
1111
12- use serde_json:: Value ;
13- use testkit:: sdk:: { SandboxPhase , SandboxRestartPolicy , SdkError } ;
14- use testkit:: { Context , Poll , Sandbox , poll_until} ;
12+ use testkit:: sdk:: { SandboxPhase , SandboxRestartPolicy } ;
13+ use testkit:: { Context , Poll , ResultExt as _, Sandbox , poll_until} ;
1514
1615/// A long-running sandbox becomes ready, runs a command with exec, and is gone
1716/// from get and list after delete.
@@ -66,22 +65,24 @@ async fn exec_outlives_startup_recovery_deadline(cx: &mut Context) -> testkit::R
6665 sandbox. exec ( [ "sh" , "-c" , script. as_str ( ) ] ) ,
6766 )
6867 . await
69- . map_err ( |_| testkit:: Error :: msg ( "exec past the recovery deadline did not finish in 60s" ) ) ??;
68+ . map_err ( |_| testkit:: Error :: msg ( "exec past the recovery deadline did not finish in 60s" ) ) ??
69+ . success ( )
70+ . context ( "the recovery deadline must not end an admitted exec" ) ?;
7071 testkit:: ensure!(
71- output. exit_code == 0 && output. stdout == "past-recovery-deadline" ,
72- "the recovery deadline must not end an admitted exec: exited {} with stdout {:?}; stderr: {}" ,
73- output. exit_code,
74- output. stdout,
75- output. stderr
72+ output. stdout == "past-recovery-deadline" ,
73+ "the exec past the recovery deadline printed {:?}" ,
74+ output. stdout
7675 ) ;
7776
78- let next = sandbox. exec ( [ "printf" , "fresh-exec" ] ) . await ?;
77+ let next = sandbox
78+ . exec ( [ "printf" , "fresh-exec" ] )
79+ . await ?
80+ . success ( )
81+ . context ( "exec after the recovery deadline" ) ?;
7982 testkit:: ensure!(
80- next. exit_code == 0 && next. stdout == "fresh-exec" ,
81- "exec after the recovery deadline exited {} with stdout {:?}; stderr: {}" ,
82- next. exit_code,
83- next. stdout,
84- next. stderr
83+ next. stdout == "fresh-exec" ,
84+ "exec after the recovery deadline printed {:?}" ,
85+ next. stdout
8586 ) ;
8687 Ok ( ( ) )
8788}
@@ -247,14 +248,7 @@ async fn main_exit_after_ready_sets_final_phase(cx: &mut Context) -> testkit::Re
247248
248249 for ( sandbox, code, phase) in & sandboxes {
249250 sandbox. wait_ready ( ) . await ?;
250- let release = sandbox. exec ( [ "touch" , RELEASE_PATH ] ) . await ?;
251- testkit:: ensure!(
252- release. exit_code == 0 ,
253- "releasing the main command of {} exited {}; stderr: {}" ,
254- sandbox. name( ) ,
255- release. exit_code,
256- release. stderr
257- ) ;
251+ sandbox. exec ( [ "touch" , RELEASE_PATH ] ) . await ?. success ( ) ?;
258252 let finished = sandbox. wait_finished ( ) . await ?;
259253 testkit:: ensure!(
260254 finished. phase == * phase && finished. exit_code == Some ( * code) ,
@@ -393,13 +387,12 @@ async fn canonical_main_environment(cx: &mut Context) -> testkit::Result {
393387
394388 let exec = sandbox
395389 . exec ( [ "sh" , "-c" , "printf '%s' \" ${REPRO_SENTINEL:-missing}\" " ] )
396- . await ?;
390+ . await ?
391+ . success ( ) ?;
397392 testkit:: ensure!(
398- exec. exit_code == 0 && exec. stdout == declared,
399- "exec (tty {tty}) saw REPRO_SENTINEL={:?}, exit {}; expected {declared:?}; stderr: {}" ,
400- exec. stdout,
401- exec. exit_code,
402- exec. stderr
393+ exec. stdout == declared,
394+ "exec (tty {tty}) saw REPRO_SENTINEL={:?}; expected {declared:?}" ,
395+ exec. stdout
403396 ) ;
404397
405398 if * tty {
499492 )
500493 . await ?;
501494
502- let initial = sandbox_details ( cx , & sandbox) . await ?;
495+ let initial = cx . sandbox_details ( sandbox. name ( ) ) . await ?;
503496 let initial_instance = initial[ "main_process_instance_id" ]
504497 . as_str ( )
505498 . unwrap_or_default ( )
508501 !initial_instance. is_empty( ) ,
509502 "sandbox get reports no main process instance: {initial}"
510503 ) ;
511- let release = sandbox
504+ sandbox
512505 . exec ( [ "touch" , "/sandbox/.openshell-restart-release" ] )
513- . await ?;
514- testkit:: ensure!(
515- release. exit_code == 0 ,
516- "releasing the initial main command exited {}; stderr: {}" ,
517- release. exit_code,
518- release. stderr
519- ) ;
506+ . await ?
507+ . success ( ) ?;
520508
521509 let restarted = poll_until (
522510 "the on-failure restart" ,
523511 RESTART_TIMEOUT ,
524512 Duration :: from_millis ( 250 ) ,
525513 async || {
526- let details = sandbox_details ( cx , & sandbox) . await ?;
514+ let details = cx . sandbox_details ( sandbox. name ( ) ) . await ?;
527515 let instance = details[ "main_process_instance_id" ]
528516 . as_str ( )
529517 . unwrap_or_default ( ) ;
558546 Ok ( ( ) )
559547}
560548
561- /// `sandbox get --output json`, which reports the main process instance and
562- /// restart policy that the SDK does not expose.
563- async fn sandbox_details ( cx : & Context , sandbox : & Sandbox ) -> testkit:: Result < Value > {
564- cx. cli ( [ "sandbox" , "get" , sandbox. name ( ) , "--output" , "json" ] )
565- . await ?
566- . success ( ) ?
567- . json ( )
568- }
569-
570549/// How long the gateway may take to remove an ephemeral sandbox after its
571550/// main command exits. Both sandboxes are released before the test waits, so
572551/// their removals overlap.
@@ -578,55 +557,29 @@ const EPHEMERAL_CLEANUP_TIMEOUT: Duration = Duration::from_secs(60);
578557async fn detached_no_keep_sandbox_is_removed_after_main_exits ( cx : & mut Context ) -> testkit:: Result {
579558 let mut sandboxes = Vec :: new ( ) ;
580559 for ( suffix, code) in [ ( "ez" , 0 ) , ( "ef" , 17 ) ] {
581- let name = cx. name ( suffix) ;
582- let release_path = format ! ( "/sandbox/.ephemeral-release-{name}" ) ;
560+ let builder = cx. cli_sandbox ( suffix) ;
561+ let release_path = format ! ( "/sandbox/.ephemeral-release-{}" , builder . name ( ) ) ;
583562 let script =
584563 format ! ( "while [ ! -e '{release_path}' ]; do sleep 0.1; done; sleep 1; exit {code}" ) ;
585- cx. track ( & name) ;
586- cx. cli ( [
587- "sandbox" ,
588- "create" ,
589- "--name" ,
590- & name,
591- "--no-keep" ,
592- "--detach" ,
593- "--" ,
594- "sh" ,
595- "-c" ,
596- & script,
597- ] )
598- . await ?
599- . success ( ) ?;
600- sandboxes. push ( ( cx. adopt ( & name) . await ?, release_path, code) ) ;
564+ let sandbox = builder
565+ . args ( [ "--no-keep" ] )
566+ . command ( [ "sh" , "-c" , & script] )
567+ . create ( )
568+ . await ?;
569+ sandboxes. push ( ( sandbox, release_path, code) ) ;
601570 }
602571
603572 for ( sandbox, release_path, _) in & sandboxes {
604573 sandbox. wait_ready ( ) . await ?;
605- let release = sandbox. exec ( [ "touch" , release_path. as_str ( ) ] ) . await ?;
606- testkit:: ensure!(
607- release. exit_code == 0 ,
608- "releasing the main command of {} exited {}; stderr: {}" ,
609- sandbox. name( ) ,
610- release. exit_code,
611- release. stderr
612- ) ;
574+ sandbox
575+ . exec ( [ "touch" , release_path. as_str ( ) ] )
576+ . await ?
577+ . success ( ) ?;
613578 }
614579 for ( sandbox, _, code) in & sandboxes {
615- poll_until (
616- & format ! (
617- "ephemeral sandbox {} to be removed after exiting {code}" ,
618- sandbox. name( )
619- ) ,
620- EPHEMERAL_CLEANUP_TIMEOUT ,
621- Duration :: from_millis ( 500 ) ,
622- async || match cx. client ( ) . get_sandbox ( sandbox. name ( ) ) . await {
623- Err ( SdkError :: NotFound { .. } ) => Ok ( Poll :: Ready ( ( ) ) ) ,
624- Err ( error) => Err ( error. into ( ) ) ,
625- Ok ( found) => Ok ( Poll :: Pending ( format ! ( "phase {:?}" , found. phase) ) ) ,
626- } ,
627- )
628- . await ?;
629- cx. expect_absent ( sandbox) . await ?;
580+ cx. wait_absent ( sandbox, EPHEMERAL_CLEANUP_TIMEOUT )
581+ . await
582+ . context ( format ! ( "ephemeral sandbox exited {code}" ) ) ?;
630583 }
631584 Ok ( ( ) )
632585}
0 commit comments