From 9ec63c0dc3825a18106933e8f36410ed4991ebc9 Mon Sep 17 00:00:00 2001 From: Enrique Saurez Date: Thu, 22 Oct 2026 22:20:32 -0700 Subject: [PATCH 1/2] nvx-rs: let the store's launch tests wait for a log that a test's child holds A process that a concurrent test spawns holds the test's descriptors from its fork until it executes its program, and with them the claim of a launch's log that the test closed, for longer than the claim release wait if the machine is loaded. A recovery, an abandon, or the check of a recorded VMM that cannot be held then ends as indeterminate. an_abandoned_launch_that_spawned_nothing_has_exited and a_recorded_vmm_that_cannot_be_held_has_exited_once_its_log_is_released expected Exited at once. Accept an indeterminate abandon, and wait with released() for a later recovery or check to end the launch, as c32b50ee does for the staging test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: bba527e3-2680-407f-ba91-a21eeb2ea18a --- nvx-rs/src/host/store/tests.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/nvx-rs/src/host/store/tests.rs b/nvx-rs/src/host/store/tests.rs index 9459c2343..3ebede73f 100644 --- a/nvx-rs/src/host/store/tests.rs +++ b/nvx-rs/src/host/store/tests.rs @@ -748,9 +748,17 @@ fn an_abandoned_launch_that_spawned_nothing_has_exited() { error.message().contains("must be recovered first"), "{error}" ); - assert_eq!(locked.recover().unwrap(), Recovery::Exited); + // A process that a concurrent test spawned may still hold the log that the launch closed, + // until it executes its program, and a later recovery then ends the launch. + assert!(released(|| locked.recover().unwrap() == Recovery::Exited)); let launch = locked.begin_launch(&runtime(), &CAPABILITY).unwrap(); - assert_eq!(launch.abandon().unwrap(), Recovery::Exited); + match launch.abandon().unwrap() { + Recovery::Exited => {} + Recovery::Indeterminate(_) => { + assert!(released(|| locked.recover().unwrap() == Recovery::Exited)); + } + other => panic!("{other:?}"), + } assert!(store.journal().unwrap().is_none()); assert!(!store.capability_path().exists()); } @@ -783,13 +791,12 @@ fn a_recorded_vmm_that_cannot_be_held_has_exited_once_its_log_is_released() { }; assert!(reason.contains("still holds its log"), "{reason}"); } - // Once nothing holds the log, the launch has exited. + // Once nothing holds the log, the launch has exited. A process that a concurrent test spawned + // may still hold it, until it executes its program. drop(log); for open in opens { - assert_eq!( - locked.end_identified(&journal, &reference, open), - Recovery::Exited - ); + let exited = || locked.end_identified(&journal, &reference, open) == Recovery::Exited; + assert!(released(exited)); } } From aa2c6f0e75d1918ae3569937108ea0832004ecdb Mon Sep 17 00:00:00 2001 From: Enrique Saurez Date: Thu, 22 Oct 2026 22:20:32 -0700 Subject: [PATCH 2/2] aci_edge_sandboxes: retry the start that a test's child delays unrecorded_launches_end_once_their_log_is_released starts the sandbox once it releases the log of a launch that it began itself. A process that a concurrent test spawned while the log was open holds it until it executes its program, for longer than the claim release wait if the machine is loaded, and the start then fails as indeterminate, with BackendError. Retry such a start for up to 10 seconds, as a caller retries an indeterminate recovery, and fail on any other error. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: bba527e3-2680-407f-ba91-a21eeb2ea18a --- aci_edge_sandboxes/tests/openvmm_fake.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/aci_edge_sandboxes/tests/openvmm_fake.rs b/aci_edge_sandboxes/tests/openvmm_fake.rs index 5e5c10128..2857be24c 100644 --- a/aci_edge_sandboxes/tests/openvmm_fake.rs +++ b/aci_edge_sandboxes/tests/openvmm_fake.rs @@ -1275,9 +1275,15 @@ fn unrecorded_launches_end_once_their_log_is_released() { } assert!(journal.exists()); - // Its release proves it. + // Its release proves it, once a process that a concurrent test spawned, which may still hold + // the log until it executes its program, has done so. drop(log); - nvx.start(&sandbox_id).unwrap(); + let deadline = Instant::now() + Duration::from_secs(10); + while let Err(error) = nvx.start(&sandbox_id) { + assert_eq!(error.code(), ErrorCode::BackendError, "{error}"); + assert!(Instant::now() < deadline, "{error}"); + thread::sleep(Duration::from_millis(25)); + } assert!(!journal.exists()); assert_eq!(run(&nvx, &sandbox_id, "echo started").stdout, b"started\n"); nvx.stop(&sandbox_id).unwrap();