From 6ab3ae532346a7e900bcef8323a0a18f3764b504 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 8 Sep 2026 22:12:06 +0000 Subject: [PATCH] Stabilize subagent and unified exec test fixtures (#43936) ## What changed - Match parent follow-up responses by tool call IDs in the grandchild context baseline test, and assert that the grandchild completes with `done`. - Drive delayed terminal output with newline-delimited stdin instead of sleeps, keeping the process alive across three `write_stdin` calls and updating the expected stdin events. GitOrigin-RevId: 433954e5ed5ecce920cf198d1bf1264e58178ba6 --- .../tests/suite/subagent_notifications.rs | 28 +++++++++++++------ codex-rs/core/tests/suite/unified_exec.rs | 18 ++++++------ 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/codex-rs/core/tests/suite/subagent_notifications.rs b/codex-rs/core/tests/suite/subagent_notifications.rs index 4adf018bc6..f3c7503ec2 100644 --- a/codex-rs/core/tests/suite/subagent_notifications.rs +++ b/codex-rs/core/tests/suite/subagent_notifications.rs @@ -67,7 +67,10 @@ use tokio::time::sleep; use tokio::time::timeout; use tracing::Level; use tracing_test::internal::MockWriter; +use wiremock::Mock; use wiremock::MockServer; +use wiremock::matchers::method; +use wiremock::matchers::path; const SPAWN_CALL_ID: &str = "spawn-call-1"; const MULTI_AGENT_V1_NAMESPACE: &str = "multi_agent_v1"; @@ -1264,14 +1267,17 @@ async fn grandchild_full_fork_preserves_context_baseline( ]), ) .await; - let _parent_followups = mount_sse_sequence( - &server, - vec![ - sse(vec![ev_completed("baseline-parent-finished-1")]), - sse(vec![ev_completed("baseline-parent-finished-2")]), - ], - ) - .await; + Mock::given(method("POST")) + .and(path("/v1/responses")) + .and(|req: &wiremock::Request| { + body_contains(req, ROOT_CALL) || body_contains(req, CHILD_CALL) + }) + .respond_with(sse_response(sse(vec![ev_completed( + "baseline-parent-finished", + )]))) + .with_priority(/*p*/ 6) + .mount(&server) + .await; let test = test_codex() .with_history_mode(history_mode) .with_config(move |config| { @@ -1337,6 +1343,12 @@ async fn grandchild_full_fork_preserves_context_baseline( } }) .await?; + if agent_name == "/root/child/grandchild" { + assert_eq!( + thread.agent_status().await, + AgentStatus::Completed(Some("done".to_string())) + ); + } descendant_requests.push(request); } let context_counts = [ diff --git a/codex-rs/core/tests/suite/unified_exec.rs b/codex-rs/core/tests/suite/unified_exec.rs index ad3f248717..5d46700446 100644 --- a/codex-rs/core/tests/suite/unified_exec.rs +++ b/codex-rs/core/tests/suite/unified_exec.rs @@ -1588,8 +1588,8 @@ async fn unified_exec_emits_terminal_interaction_for_write_stdin( #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn unified_exec_terminal_interaction_captures_delayed_output() -> Result<()> { - // TODO(anp): Remove after timing fixtures use target-native commands. - skip_if_target_windows!(Ok(()), "uses a POSIX sleep/echo timing fixture"); + // TODO(anp): Remove after interactive fixtures use target-native commands. + skip_if_target_windows!(Ok(()), "uses a POSIX read/printf fixture"); skip_if_no_network!(Ok(())); skip_if_sandbox!(Ok(())); @@ -1600,30 +1600,30 @@ async fn unified_exec_terminal_interaction_captures_delayed_output() -> Result<( let open_call_id = "uexec-delayed-open"; let open_args = json!({ - "cmd": "sleep 3 && echo MARKER1 && sleep 3 && echo MARKER2", + "cmd": r#"/bin/sh -c 'read -r input && read -r input && printf "MARKER1\n" && read -r input && printf "MARKER2\n"'"#, "yield_time_ms": 10, "tty": true, }); - // Poll stdin three times: first for no output, second after the first marker, - // and a final long poll to capture the second marker. + // The second and third input lines produce the markers. Waiting for the third + // line keeps the process alive across all three write_stdin calls. let first_poll_call_id = "uexec-delayed-poll-1"; let first_poll_args = json!({ - "chars": "x", + "chars": "x\n", "session_id": 1000, "yield_time_ms": 10, }); let second_poll_call_id = "uexec-delayed-poll-2"; let second_poll_args = json!({ - "chars": "x", + "chars": "x\n", "session_id": 1000, "yield_time_ms": 4000, }); let third_poll_call_id = "uexec-delayed-poll-3"; let third_poll_args = json!({ - "chars": "x", + "chars": "x\n", "session_id": 1000, "yield_time_ms": 6000, }); @@ -1734,7 +1734,7 @@ async fn unified_exec_terminal_interaction_captures_delayed_output() -> Result<( .iter() .map(|ev| ev.stdin.as_str()) .collect::>(), - vec!["x", "x", "x"], + vec!["x\n", "x\n", "x\n"], "terminal interactions should reflect the three stdin polls" );