From 6703333d2a7a35d44b7378cfecf2ca3f534146b3 Mon Sep 17 00:00:00 2001 From: Joe Gershenson Date: Tue, 14 Apr 2026 22:35:27 -0700 Subject: [PATCH 01/13] Fix Windows marketplace local source parsing --- .../core/src/plugins/marketplace_add/source.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/codex-rs/core/src/plugins/marketplace_add/source.rs b/codex-rs/core/src/plugins/marketplace_add/source.rs index 53d52058aa0..2a49d925dfb 100644 --- a/codex-rs/core/src/plugins/marketplace_add/source.rs +++ b/codex-rs/core/src/plugins/marketplace_add/source.rs @@ -130,6 +130,16 @@ fn looks_like_local_path(source: &str) -> bool { || source.starts_with("~/") || source == "." || source == ".." + || { + #[cfg(windows)] + { + source.starts_with(".\\") || source.starts_with("..\\") || source.starts_with('\\') + } + #[cfg(not(windows))] + { + false + } + } } fn resolve_local_source_path(source: &str) -> Result { @@ -310,6 +320,14 @@ mod tests { assert!(path.is_absolute()); } + #[cfg(windows)] + #[test] + fn windows_backslash_relative_path_looks_local() { + assert!(looks_like_local_path(r".\marketplace")); + assert!(looks_like_local_path(r"..\marketplace")); + assert!(looks_like_local_path(r"\marketplace")); + } + #[test] fn local_file_source_is_rejected() { let tempdir = TempDir::new().unwrap(); From d61d3136a63e4b5b84acdd85d59ff1d844b05d03 Mon Sep 17 00:00:00 2001 From: Joe Gershenson Date: Tue, 14 Apr 2026 23:33:03 -0700 Subject: [PATCH 02/13] Stabilize Windows thread unsubscribe sleep test --- codex-rs/app-server/tests/common/lib.rs | 1 + codex-rs/app-server/tests/common/responses.rs | 26 ++++++++++++++++--- .../tests/suite/v2/thread_unsubscribe.rs | 15 +++++------ 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/codex-rs/app-server/tests/common/lib.rs b/codex-rs/app-server/tests/common/lib.rs index 6bb73721629..2c06248da57 100644 --- a/codex-rs/app-server/tests/common/lib.rs +++ b/codex-rs/app-server/tests/common/lib.rs @@ -37,6 +37,7 @@ pub use responses::create_final_assistant_message_sse_response; pub use responses::create_request_permissions_sse_response; pub use responses::create_request_user_input_sse_response; pub use responses::create_shell_command_sse_response; +pub use responses::create_shell_command_sse_response_from_command; pub use rollout::create_fake_rollout; pub use rollout::create_fake_rollout_with_source; pub use rollout::create_fake_rollout_with_text_elements; diff --git a/codex-rs/app-server/tests/common/responses.rs b/codex-rs/app-server/tests/common/responses.rs index 586d1446c07..8deda2fc27e 100644 --- a/codex-rs/app-server/tests/common/responses.rs +++ b/codex-rs/app-server/tests/common/responses.rs @@ -10,11 +10,31 @@ pub fn create_shell_command_sse_response( ) -> anyhow::Result { // The `arguments` for the `shell_command` tool is a serialized JSON object. let command_str = shlex::try_join(command.iter().map(String::as_str))?; - let tool_call_arguments = serde_json::to_string(&json!({ - "command": command_str, + create_shell_command_sse_response_from_command(&command_str, workdir, timeout_ms, call_id, None) +} + +pub fn create_shell_command_sse_response_from_command( + command: &str, + workdir: Option<&Path>, + timeout_ms: Option, + call_id: &str, + login: Option, +) -> anyhow::Result { + // Use this when a test already has a shell command string. It fixes string + // quoting for those callers by avoiding a rebuild from argv with POSIX + // rules, which can change how Windows PowerShell parses the command; for + // sleep-based tests, nested parsing can add another PowerShell startup + // before the requested sleep even begins. + let mut tool_call_arguments = json!({ + "command": command, "workdir": workdir.map(|w| w.to_string_lossy()), "timeout_ms": timeout_ms - }))?; + }); + if let Some(login) = login { + tool_call_arguments["login"] = json!(login); + } + + let tool_call_arguments = serde_json::to_string(&tool_call_arguments)?; Ok(responses::sse(vec![ responses::ev_response_created("resp-1"), responses::ev_function_call(call_id, "shell_command", &tool_call_arguments), diff --git a/codex-rs/app-server/tests/suite/v2/thread_unsubscribe.rs b/codex-rs/app-server/tests/suite/v2/thread_unsubscribe.rs index 6aab3d186f9..41ad4ecda62 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_unsubscribe.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_unsubscribe.rs @@ -4,7 +4,7 @@ use app_test_support::McpProcess; use app_test_support::create_final_assistant_message_sse_response; use app_test_support::create_mock_responses_server_repeating_assistant; use app_test_support::create_mock_responses_server_sequence_unchecked; -use app_test_support::create_shell_command_sse_response; +use app_test_support::create_shell_command_sse_response_from_command; use app_test_support::to_response; use codex_app_server_protocol::ItemStartedNotification; use codex_app_server_protocol::JSONRPCResponse; @@ -129,13 +129,9 @@ async fn thread_unsubscribe_keeps_thread_loaded_until_idle_timeout() -> Result<( #[tokio::test] async fn thread_unsubscribe_during_turn_keeps_turn_running() -> Result<()> { #[cfg(target_os = "windows")] - let shell_command = vec![ - "powershell".to_string(), - "-Command".to_string(), - "Start-Sleep -Seconds 1".to_string(), - ]; + let shell_command = "Start-Sleep -Seconds 1"; #[cfg(not(target_os = "windows"))] - let shell_command = vec!["sleep".to_string(), "1".to_string()]; + let shell_command = "sleep 1"; let tmp = TempDir::new()?; let codex_home = tmp.path().join("codex_home"); @@ -144,11 +140,12 @@ async fn thread_unsubscribe_during_turn_keeps_turn_running() -> Result<()> { std::fs::create_dir(&working_directory)?; let server = create_mock_responses_server_sequence_unchecked(vec![ - create_shell_command_sse_response( - shell_command.clone(), + create_shell_command_sse_response_from_command( + shell_command, Some(&working_directory), Some(10_000), "call_sleep", + Some(false), )?, create_final_assistant_message_sse_response("Done")?, ]) From 6a3962f74975da931ab6c20acffb0962746f4a62 Mon Sep 17 00:00:00 2001 From: Joe Gershenson Date: Tue, 14 Apr 2026 23:51:34 -0700 Subject: [PATCH 03/13] Fix marketplace config test and argument lint --- codex-rs/app-server/tests/common/responses.rs | 8 +++++++- codex-rs/core/src/plugins/marketplace_add.rs | 10 ++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/codex-rs/app-server/tests/common/responses.rs b/codex-rs/app-server/tests/common/responses.rs index 8deda2fc27e..6044218c67e 100644 --- a/codex-rs/app-server/tests/common/responses.rs +++ b/codex-rs/app-server/tests/common/responses.rs @@ -10,7 +10,13 @@ pub fn create_shell_command_sse_response( ) -> anyhow::Result { // The `arguments` for the `shell_command` tool is a serialized JSON object. let command_str = shlex::try_join(command.iter().map(String::as_str))?; - create_shell_command_sse_response_from_command(&command_str, workdir, timeout_ms, call_id, None) + create_shell_command_sse_response_from_command( + &command_str, + workdir, + timeout_ms, + call_id, + /*login*/ None, + ) } pub fn create_shell_command_sse_response_from_command( diff --git a/codex-rs/core/src/plugins/marketplace_add.rs b/codex-rs/core/src/plugins/marketplace_add.rs index b8d1b34d419..e02eefe6daf 100644 --- a/codex-rs/core/src/plugins/marketplace_add.rs +++ b/codex-rs/core/src/plugins/marketplace_add.rs @@ -276,12 +276,18 @@ mod tests { let config = fs::read_to_string(codex_home.path().join(codex_config::CONFIG_TOML_FILE))?; let config: toml::Value = toml::from_str(&config)?; + let marketplace = config + .get("marketplaces") + .and_then(toml::Value::as_table) + .and_then(|marketplaces| marketplaces.get("debug")) + .and_then(toml::Value::as_table) + .expect("debug marketplace should be present in config"); assert_eq!( - config["marketplaces"]["debug"]["source_type"].as_str(), + marketplace.get("source_type").and_then(toml::Value::as_str), Some("local") ); assert_eq!( - config["marketplaces"]["debug"]["source"].as_str(), + marketplace.get("source").and_then(toml::Value::as_str), Some(expected_source.as_str()) ); Ok(()) From 7e47e850da60bc610914baff9e518a740eeda403 Mon Sep 17 00:00:00 2001 From: Joe Gershenson Date: Wed, 15 Apr 2026 00:34:47 -0700 Subject: [PATCH 04/13] Stabilize multi-agent interrupt test --- .../src/tools/handlers/multi_agents_tests.rs | 73 ++++++++++++++----- 1 file changed, 53 insertions(+), 20 deletions(-) diff --git a/codex-rs/core/src/tools/handlers/multi_agents_tests.rs b/codex-rs/core/src/tools/handlers/multi_agents_tests.rs index 10f41d97eb4..64d270ad0d8 100644 --- a/codex-rs/core/src/tools/handlers/multi_agents_tests.rs +++ b/codex-rs/core/src/tools/handlers/multi_agents_tests.rs @@ -55,6 +55,7 @@ use std::path::PathBuf; use std::sync::Arc; use std::time::Duration; use tokio::sync::Mutex; +use tokio::sync::Notify; use tokio::time::timeout; use tokio_util::sync::CancellationToken; @@ -153,26 +154,28 @@ async fn wait_for_turn_aborted( expected_turn_id: &str, expected_reason: TurnAbortReason, ) { - timeout(Duration::from_secs(5), async { - loop { - let event = thread - .next_event() - .await - .expect("child thread should emit events"); - if matches!( - event.msg, - EventMsg::TurnAborted(TurnAbortedEvent { - turn_id: Some(ref turn_id), - ref reason, - .. - }) if turn_id == expected_turn_id && *reason == expected_reason - ) { + let deadline = tokio::time::Instant::now() + Duration::from_secs(15); + let mut seen_aborts = Vec::new(); + loop { + let remaining = deadline.saturating_duration_since(tokio::time::Instant::now()); + let event = timeout(remaining, thread.next_event()) + .await + .unwrap_or_else(|_| { + panic!( + "expected child turn {expected_turn_id} to be aborted with {expected_reason:?}; saw aborts: {seen_aborts:?}" + ) + }) + .expect("child thread should emit events"); + if let EventMsg::TurnAborted(TurnAbortedEvent { + turn_id, reason, .. + }) = event.msg + { + if turn_id.as_deref() == Some(expected_turn_id) && reason == expected_reason { break; } + seen_aborts.push((turn_id, reason)); } - }) - .await - .expect("expected child turn to be interrupted"); + } } async fn wait_for_redirected_envelope_in_history( @@ -216,8 +219,9 @@ async fn wait_for_redirected_envelope_in_history( .expect("redirected followup envelope should appear in history"); } -#[derive(Clone, Copy)] -struct NeverEndingTask; +struct NeverEndingTask { + started: Arc, +} impl SessionTask for NeverEndingTask { fn kind(&self) -> TaskKind { @@ -235,6 +239,7 @@ impl SessionTask for NeverEndingTask { _input: Vec, cancellation_token: CancellationToken, ) -> Option { + self.started.notify_one(); cancellation_token.cancelled().await; None } @@ -1516,8 +1521,28 @@ async fn multi_agent_v2_followup_task_interrupts_busy_child_without_losing_messa .await .expect("worker thread should exist"); + timeout(Duration::from_secs(15), async { + loop { + let event = thread + .next_event() + .await + .expect("child thread should emit initial turn events"); + if matches!(event.msg, EventMsg::TurnStarted(_)) { + break; + } + } + }) + .await + .expect("spawned child task should start before test injects a busy task"); + thread + .codex + .session + .abort_all_tasks(TurnAbortReason::Replaced) + .await; + let active_turn = thread.codex.session.new_default_turn().await; let interrupted_turn_id = active_turn.sub_id.clone(); + let never_ending_task_started = Arc::new(Notify::new()); thread .codex .session @@ -1527,9 +1552,17 @@ async fn multi_agent_v2_followup_task_interrupts_busy_child_without_losing_messa text: "working".to_string(), text_elements: Vec::new(), }], - NeverEndingTask, + NeverEndingTask { + started: Arc::clone(&never_ending_task_started), + }, ) .await; + timeout( + Duration::from_secs(15), + never_ending_task_started.notified(), + ) + .await + .expect("child task should start before the interrupting followup"); FollowupTaskHandlerV2 .handle(invocation( From a3719d9052daf3307a6b329898b250396b8777d2 Mon Sep 17 00:00:00 2001 From: Joe Gershenson Date: Wed, 15 Apr 2026 00:56:01 -0700 Subject: [PATCH 05/13] Use NoProfile in PowerShell exec tests --- codex-rs/core/src/exec_tests.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/codex-rs/core/src/exec_tests.rs b/codex-rs/core/src/exec_tests.rs index acc92f5585d..0f7dd3eaa80 100644 --- a/codex-rs/core/src/exec_tests.rs +++ b/codex-rs/core/src/exec_tests.rs @@ -252,6 +252,7 @@ async fn exec_full_buffer_capture_ignores_expiration() -> Result<()> { "powershell.exe".to_string(), "-NonInteractive".to_string(), "-NoLogo".to_string(), + "-NoProfile".to_string(), "-Command".to_string(), "Start-Sleep -Milliseconds 50; [Console]::Out.Write('hello')".to_string(), ]; @@ -334,6 +335,7 @@ async fn process_exec_tool_call_preserves_full_buffer_capture_policy() -> Result "powershell.exe".to_string(), "-NonInteractive".to_string(), "-NoLogo".to_string(), + "-NoProfile".to_string(), "-Command".to_string(), format!("Start-Sleep -Milliseconds 50; [Console]::Out.Write('a' * {byte_count})"), ]; @@ -1014,6 +1016,7 @@ fn long_running_command() -> Vec { "powershell.exe".to_string(), "-NonInteractive".to_string(), "-NoLogo".to_string(), + "-NoProfile".to_string(), "-Command".to_string(), "Start-Sleep -Seconds 30".to_string(), ] From a04370f703d49f4fd430cee8ce0320d1a8653821 Mon Sep 17 00:00:00 2001 From: Joe Gershenson Date: Wed, 15 Apr 2026 09:58:36 -0700 Subject: [PATCH 06/13] Fix multi-agent interrupt test startup wait --- .../src/tools/handlers/multi_agents_tests.rs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/codex-rs/core/src/tools/handlers/multi_agents_tests.rs b/codex-rs/core/src/tools/handlers/multi_agents_tests.rs index 64d270ad0d8..a06c5c23767 100644 --- a/codex-rs/core/src/tools/handlers/multi_agents_tests.rs +++ b/codex-rs/core/src/tools/handlers/multi_agents_tests.rs @@ -1521,25 +1521,6 @@ async fn multi_agent_v2_followup_task_interrupts_busy_child_without_losing_messa .await .expect("worker thread should exist"); - timeout(Duration::from_secs(15), async { - loop { - let event = thread - .next_event() - .await - .expect("child thread should emit initial turn events"); - if matches!(event.msg, EventMsg::TurnStarted(_)) { - break; - } - } - }) - .await - .expect("spawned child task should start before test injects a busy task"); - thread - .codex - .session - .abort_all_tasks(TurnAbortReason::Replaced) - .await; - let active_turn = thread.codex.session.new_default_turn().await; let interrupted_turn_id = active_turn.sub_id.clone(); let never_ending_task_started = Arc::new(Notify::new()); From c7d99c63cf9da6255933ee6f21e731831dcb2c8d Mon Sep 17 00:00:00 2001 From: Joe Gershenson Date: Wed, 15 Apr 2026 10:28:05 -0700 Subject: [PATCH 07/13] Stabilize Bazel test timing under load --- codex-rs/app-server/BUILD.bazel | 1 + codex-rs/core/src/tools/handlers/multi_agents_tests.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/codex-rs/app-server/BUILD.bazel b/codex-rs/app-server/BUILD.bazel index f32f811627b..0930670ca56 100644 --- a/codex-rs/app-server/BUILD.bazel +++ b/codex-rs/app-server/BUILD.bazel @@ -6,6 +6,7 @@ codex_rust_crate( integration_test_tags_extra_by_stem = { "all": ["flaky"], }, + integration_test_args = ["--test-threads=4"], integration_test_timeout = "long", test_tags = ["no-sandbox"], ) diff --git a/codex-rs/core/src/tools/handlers/multi_agents_tests.rs b/codex-rs/core/src/tools/handlers/multi_agents_tests.rs index a06c5c23767..bfa46f45bfe 100644 --- a/codex-rs/core/src/tools/handlers/multi_agents_tests.rs +++ b/codex-rs/core/src/tools/handlers/multi_agents_tests.rs @@ -182,7 +182,7 @@ async fn wait_for_redirected_envelope_in_history( thread: &Arc, expected: &InterAgentCommunication, ) { - timeout(Duration::from_secs(5), async { + timeout(Duration::from_secs(30), async { loop { let history_items = thread .codex From b0bea0225b9f6af5ca0bbe9f3b43a8314b51fcce Mon Sep 17 00:00:00 2001 From: Joe Gershenson Date: Wed, 15 Apr 2026 11:01:25 -0700 Subject: [PATCH 08/13] Stabilize remaining Bazel timing flakes --- codex-rs/app-server/BUILD.bazel | 2 +- codex-rs/app-server/tests/suite/auth.rs | 20 +++++++++++++++++++ codex-rs/core/src/agent/control_tests.rs | 2 +- codex-rs/mcp-server/tests/common/responses.rs | 1 + codex-rs/mcp-server/tests/suite/codex_tool.rs | 11 +++++----- 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/codex-rs/app-server/BUILD.bazel b/codex-rs/app-server/BUILD.bazel index 0930670ca56..165fef218ee 100644 --- a/codex-rs/app-server/BUILD.bazel +++ b/codex-rs/app-server/BUILD.bazel @@ -6,7 +6,7 @@ codex_rust_crate( integration_test_tags_extra_by_stem = { "all": ["flaky"], }, - integration_test_args = ["--test-threads=4"], + integration_test_args = ["--test-threads=2"], integration_test_timeout = "long", test_tags = ["no-sandbox"], ) diff --git a/codex-rs/app-server/tests/suite/auth.rs b/codex-rs/app-server/tests/suite/auth.rs index e6134e48024..4044c2fa928 100644 --- a/codex-rs/app-server/tests/suite/auth.rs +++ b/codex-rs/app-server/tests/suite/auth.rs @@ -17,6 +17,7 @@ use codex_login::REFRESH_TOKEN_URL_OVERRIDE_ENV_VAR; use pretty_assertions::assert_eq; use std::path::Path; use tempfile::TempDir; +use tokio::time::sleep; use tokio::time::timeout; use wiremock::Mock; use wiremock::MockServer; @@ -26,6 +27,23 @@ use wiremock::matchers::path; const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +async fn wait_for_received_requests(server: &MockServer, expected: usize) -> Result<()> { + timeout(DEFAULT_READ_TIMEOUT, async { + loop { + let received = server + .received_requests() + .await + .map_or(0, |requests| requests.len()); + if received >= expected { + break; + } + sleep(std::time::Duration::from_millis(25)).await; + } + }) + .await?; + Ok(()) +} + fn create_config_toml_custom_provider( codex_home: &Path, requires_openai_auth: bool, @@ -373,6 +391,7 @@ async fn get_auth_status_omits_token_after_proactive_refresh_failure() -> Result ) .await?; timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??; + wait_for_received_requests(&server, 1).await?; let request_id = mcp .send_get_auth_status_request(GetAuthStatusParams { @@ -440,6 +459,7 @@ async fn get_auth_status_returns_token_after_proactive_refresh_recovery() -> Res ) .await?; timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??; + wait_for_received_requests(&server, 1).await?; let failed_request_id = mcp .send_get_auth_status_request(GetAuthStatusParams { diff --git a/codex-rs/core/src/agent/control_tests.rs b/codex-rs/core/src/agent/control_tests.rs index 6fc74b30e86..06184c23091 100644 --- a/codex-rs/core/src/agent/control_tests.rs +++ b/codex-rs/core/src/agent/control_tests.rs @@ -186,7 +186,7 @@ async fn wait_for_subagent_notification(parent_thread: &Arc) -> boo sleep(Duration::from_millis(25)).await; } }; - timeout(Duration::from_secs(2), wait).await.is_ok() + timeout(Duration::from_secs(30), wait).await.is_ok() } async fn persist_thread_for_tree_resume(thread: &Arc, message: &str) { diff --git a/codex-rs/mcp-server/tests/common/responses.rs b/codex-rs/mcp-server/tests/common/responses.rs index 48a575a4c6b..9d93d3dec26 100644 --- a/codex-rs/mcp-server/tests/common/responses.rs +++ b/codex-rs/mcp-server/tests/common/responses.rs @@ -14,6 +14,7 @@ pub fn create_shell_command_sse_response( "command": command_str, "workdir": workdir.map(|w| w.to_string_lossy()), "timeout_ms": timeout_ms, + "login": false, }))?; let response_id = format!("resp-{call_id}"); Ok(responses::sse(vec![ diff --git a/codex-rs/mcp-server/tests/suite/codex_tool.rs b/codex-rs/mcp-server/tests/suite/codex_tool.rs index f8896864bc0..7ea221932c1 100644 --- a/codex-rs/mcp-server/tests/suite/codex_tool.rs +++ b/codex-rs/mcp-server/tests/suite/codex_tool.rs @@ -27,7 +27,7 @@ use mcp_test_support::create_apply_patch_sse_response; use mcp_test_support::create_final_assistant_message_sse_response; use mcp_test_support::create_mock_responses_server; use mcp_test_support::create_shell_command_sse_response; -use mcp_test_support::format_with_current_shell; +use mcp_test_support::format_with_current_shell_non_login; // Allow ample time on slower CI or under load to avoid flakes. const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(20); @@ -70,8 +70,8 @@ async fn shell_command_approval_triggers_elicitation() -> anyhow::Result<()> { created_filename.to_string(), "-Force".to_string(), ], - // `powershell.exe` startup can be slow on loaded Windows CI workers - 10_000, + // `powershell.exe` startup can be slow on loaded Windows CI workers. + 30_000, ) } else { ( @@ -79,8 +79,9 @@ async fn shell_command_approval_triggers_elicitation() -> anyhow::Result<()> { 5_000, ) }; - let expected_shell_command = - format_with_current_shell(&shlex::try_join(shell_command.iter().map(String::as_str))?); + let expected_shell_command = format_with_current_shell_non_login(&shlex::try_join( + shell_command.iter().map(String::as_str), + )?); let McpHandle { process: mut mcp_process, From 63230bc9b9cf46191708f47a7bfc98698ad99f5c Mon Sep 17 00:00:00 2001 From: Joe Gershenson Date: Wed, 15 Apr 2026 11:13:18 -0700 Subject: [PATCH 09/13] Fix app-server argument lint --- codex-rs/app-server/tests/suite/auth.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codex-rs/app-server/tests/suite/auth.rs b/codex-rs/app-server/tests/suite/auth.rs index 4044c2fa928..b324c4abca9 100644 --- a/codex-rs/app-server/tests/suite/auth.rs +++ b/codex-rs/app-server/tests/suite/auth.rs @@ -391,7 +391,7 @@ async fn get_auth_status_omits_token_after_proactive_refresh_failure() -> Result ) .await?; timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??; - wait_for_received_requests(&server, 1).await?; + wait_for_received_requests(&server, /*expected*/ 1).await?; let request_id = mcp .send_get_auth_status_request(GetAuthStatusParams { @@ -459,7 +459,7 @@ async fn get_auth_status_returns_token_after_proactive_refresh_recovery() -> Res ) .await?; timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??; - wait_for_received_requests(&server, 1).await?; + wait_for_received_requests(&server, /*expected*/ 1).await?; let failed_request_id = mcp .send_get_auth_status_request(GetAuthStatusParams { From 5676b840c2ae3f6d600940d81b5433bebb2d0dec Mon Sep 17 00:00:00 2001 From: Joe Gershenson Date: Wed, 15 Apr 2026 11:26:20 -0700 Subject: [PATCH 10/13] Fix TUI memory mode test isolation --- codex-rs/tui/src/app.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index 71304deb2cc..701fae4ca50 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -8153,6 +8153,7 @@ mod tests { let (mut app, _app_event_rx, _op_rx) = make_test_app_with_channels().await; let codex_home = tempdir()?; app.config.codex_home = codex_home.path().to_path_buf().abs(); + app.config.sqlite_home = codex_home.path().to_path_buf(); let mut app_server = crate::start_embedded_app_server_for_picker(&app.config).await?; let started = app_server.start_thread(&app.config).await?; From 55b2274989b6665a1c37dd21ed82960697be4ade Mon Sep 17 00:00:00 2001 From: Joe Gershenson Date: Wed, 15 Apr 2026 11:50:51 -0700 Subject: [PATCH 11/13] Wait for TUI memory mode persistence --- codex-rs/tui/src/app.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index 701fae4ca50..13d1d368f5e 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -8173,10 +8173,20 @@ mod tests { ) .await .expect("state db should initialize"); - let memory_mode = state_db - .get_thread_memory_mode(thread_id) - .await - .expect("thread memory mode should be readable"); + let memory_mode = time::timeout(Duration::from_secs(10), async { + loop { + let memory_mode = state_db + .get_thread_memory_mode(thread_id) + .await + .expect("thread memory mode should be readable"); + if memory_mode.as_deref() == Some("disabled") { + break memory_mode; + } + time::sleep(Duration::from_millis(50)).await; + } + }) + .await + .expect("thread memory mode should update"); assert_eq!(memory_mode.as_deref(), Some("disabled")); app_server.shutdown().await?; From 5976ceb8cc3f726d9ae6b60372f283927887698f Mon Sep 17 00:00:00 2001 From: Joe Gershenson Date: Wed, 15 Apr 2026 12:37:41 -0700 Subject: [PATCH 12/13] Stabilize app-server CI timeouts --- codex-rs/app-server/tests/suite/auth.rs | 2 +- .../app-server/tests/suite/conversation_summary.rs | 2 +- codex-rs/app-server/tests/suite/fuzzy_file_search.rs | 2 +- codex-rs/app-server/tests/suite/v2/app_list.rs | 2 +- .../app-server/tests/suite/v2/client_metadata.rs | 2 +- .../tests/suite/v2/collaboration_mode_list.rs | 2 +- codex-rs/app-server/tests/suite/v2/compaction.rs | 2 +- codex-rs/app-server/tests/suite/v2/config_rpc.rs | 2 +- .../tests/suite/v2/connection_handling_websocket.rs | 2 +- codex-rs/app-server/tests/suite/v2/dynamic_tools.rs | 2 +- .../app-server/tests/suite/v2/experimental_api.rs | 2 +- .../tests/suite/v2/experimental_feature_list.rs | 2 +- codex-rs/app-server/tests/suite/v2/fs.rs | 2 +- codex-rs/app-server/tests/suite/v2/initialize.rs | 2 +- .../app-server/tests/suite/v2/marketplace_add.rs | 2 +- codex-rs/app-server/tests/suite/v2/mcp_resource.rs | 2 +- .../tests/suite/v2/mcp_server_elicitation.rs | 2 +- .../app-server/tests/suite/v2/mcp_server_status.rs | 2 +- codex-rs/app-server/tests/suite/v2/mcp_tool.rs | 2 +- codex-rs/app-server/tests/suite/v2/memory_reset.rs | 2 +- codex-rs/app-server/tests/suite/v2/model_list.rs | 2 +- codex-rs/app-server/tests/suite/v2/output_schema.rs | 2 +- codex-rs/app-server/tests/suite/v2/plan_item.rs | 2 +- codex-rs/app-server/tests/suite/v2/plugin_install.rs | 2 +- codex-rs/app-server/tests/suite/v2/plugin_list.rs | 12 ++++++++++-- codex-rs/app-server/tests/suite/v2/plugin_read.rs | 2 +- .../app-server/tests/suite/v2/plugin_uninstall.rs | 2 +- codex-rs/app-server/tests/suite/v2/rate_limits.rs | 2 +- .../tests/suite/v2/realtime_conversation.rs | 2 +- .../app-server/tests/suite/v2/request_permissions.rs | 2 +- .../app-server/tests/suite/v2/request_user_input.rs | 2 +- codex-rs/app-server/tests/suite/v2/review.rs | 2 +- .../tests/suite/v2/safety_check_downgrade.rs | 2 +- codex-rs/app-server/tests/suite/v2/skills_list.rs | 2 +- codex-rs/app-server/tests/suite/v2/thread_archive.rs | 2 +- codex-rs/app-server/tests/suite/v2/thread_fork.rs | 2 +- .../app-server/tests/suite/v2/thread_inject_items.rs | 2 +- codex-rs/app-server/tests/suite/v2/thread_list.rs | 2 +- .../app-server/tests/suite/v2/thread_loaded_list.rs | 2 +- .../tests/suite/v2/thread_memory_mode_set.rs | 2 +- .../tests/suite/v2/thread_metadata_update.rs | 2 +- codex-rs/app-server/tests/suite/v2/thread_read.rs | 2 +- codex-rs/app-server/tests/suite/v2/thread_resume.rs | 2 +- .../app-server/tests/suite/v2/thread_rollback.rs | 2 +- .../tests/suite/v2/thread_shell_command.rs | 2 +- codex-rs/app-server/tests/suite/v2/thread_start.rs | 2 +- codex-rs/app-server/tests/suite/v2/thread_status.rs | 2 +- .../app-server/tests/suite/v2/thread_unsubscribe.rs | 2 +- codex-rs/app-server/tests/suite/v2/turn_interrupt.rs | 2 +- codex-rs/app-server/tests/suite/v2/turn_start.rs | 2 +- .../app-server/tests/suite/v2/turn_start_zsh_fork.rs | 2 +- codex-rs/app-server/tests/suite/v2/turn_steer.rs | 2 +- .../tests/suite/v2/windows_sandbox_setup.rs | 2 +- 53 files changed, 62 insertions(+), 54 deletions(-) diff --git a/codex-rs/app-server/tests/suite/auth.rs b/codex-rs/app-server/tests/suite/auth.rs index b324c4abca9..9e88467ffe7 100644 --- a/codex-rs/app-server/tests/suite/auth.rs +++ b/codex-rs/app-server/tests/suite/auth.rs @@ -25,7 +25,7 @@ use wiremock::ResponseTemplate; use wiremock::matchers::method; use wiremock::matchers::path; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); async fn wait_for_received_requests(server: &MockServer, expected: usize) -> Result<()> { timeout(DEFAULT_READ_TIMEOUT, async { diff --git a/codex-rs/app-server/tests/suite/conversation_summary.rs b/codex-rs/app-server/tests/suite/conversation_summary.rs index 4690a44ca3b..af917a0c2cf 100644 --- a/codex-rs/app-server/tests/suite/conversation_summary.rs +++ b/codex-rs/app-server/tests/suite/conversation_summary.rs @@ -15,7 +15,7 @@ use std::path::PathBuf; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); const FILENAME_TS: &str = "2025-01-02T12-00-00"; const META_RFC3339: &str = "2025-01-02T12:00:00Z"; const UPDATED_AT_RFC3339: &str = "2025-01-02T12:00:00.000Z"; diff --git a/codex-rs/app-server/tests/suite/fuzzy_file_search.rs b/codex-rs/app-server/tests/suite/fuzzy_file_search.rs index 1520d99e3eb..b40dcb8a7af 100644 --- a/codex-rs/app-server/tests/suite/fuzzy_file_search.rs +++ b/codex-rs/app-server/tests/suite/fuzzy_file_search.rs @@ -11,7 +11,7 @@ use std::path::Path; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); const SHORT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(500); const STOP_GRACE_PERIOD: std::time::Duration = std::time::Duration::from_millis(250); const SESSION_UPDATED_METHOD: &str = "fuzzyFileSearch/sessionUpdated"; diff --git a/codex-rs/app-server/tests/suite/v2/app_list.rs b/codex-rs/app-server/tests/suite/v2/app_list.rs index dbe61524f5e..bfcc42b231f 100644 --- a/codex-rs/app-server/tests/suite/v2/app_list.rs +++ b/codex-rs/app-server/tests/suite/v2/app_list.rs @@ -56,7 +56,7 @@ use tokio::net::TcpListener; use tokio::task::JoinHandle; use tokio::time::timeout; -const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); #[tokio::test] async fn list_apps_returns_empty_when_connectors_disabled() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/client_metadata.rs b/codex-rs/app-server/tests/suite/v2/client_metadata.rs index c85febd7d46..7b3c8e3298d 100644 --- a/codex-rs/app-server/tests/suite/v2/client_metadata.rs +++ b/codex-rs/app-server/tests/suite/v2/client_metadata.rs @@ -18,7 +18,7 @@ use std::path::Path; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn turn_start_forwards_client_metadata_to_responses_request_v2() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/collaboration_mode_list.rs b/codex-rs/app-server/tests/suite/v2/collaboration_mode_list.rs index 7c36827e6dd..ff408e45b34 100644 --- a/codex-rs/app-server/tests/suite/v2/collaboration_mode_list.rs +++ b/codex-rs/app-server/tests/suite/v2/collaboration_mode_list.rs @@ -21,7 +21,7 @@ use pretty_assertions::assert_eq; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); /// Confirms the server returns the default collaboration mode presets in a stable order. #[tokio::test] diff --git a/codex-rs/app-server/tests/suite/v2/compaction.rs b/codex-rs/app-server/tests/suite/v2/compaction.rs index e7661546acd..788c426aafa 100644 --- a/codex-rs/app-server/tests/suite/v2/compaction.rs +++ b/codex-rs/app-server/tests/suite/v2/compaction.rs @@ -38,7 +38,7 @@ use std::collections::BTreeMap; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); const AUTO_COMPACT_LIMIT: i64 = 1_000; const COMPACT_PROMPT: &str = "Summarize the conversation."; const INVALID_REQUEST_ERROR_CODE: i64 = -32600; diff --git a/codex-rs/app-server/tests/suite/v2/config_rpc.rs b/codex-rs/app-server/tests/suite/v2/config_rpc.rs index 5c04cc3c443..ec789067294 100644 --- a/codex-rs/app-server/tests/suite/v2/config_rpc.rs +++ b/codex-rs/app-server/tests/suite/v2/config_rpc.rs @@ -33,7 +33,7 @@ use serde_json::json; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); fn write_config(codex_home: &TempDir, contents: &str) -> Result<()> { Ok(std::fs::write( diff --git a/codex-rs/app-server/tests/suite/v2/connection_handling_websocket.rs b/codex-rs/app-server/tests/suite/v2/connection_handling_websocket.rs index 05d26d55e36..cee8cfde5ff 100644 --- a/codex-rs/app-server/tests/suite/v2/connection_handling_websocket.rs +++ b/codex-rs/app-server/tests/suite/v2/connection_handling_websocket.rs @@ -47,7 +47,7 @@ use tokio_tungstenite::tungstenite::http::HeaderValue; use tokio_tungstenite::tungstenite::http::header::AUTHORIZATION; use tokio_tungstenite::tungstenite::http::header::ORIGIN; -pub(super) const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(10); +pub(super) const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(30); pub(super) type WsClient = WebSocketStream>; type HmacSha256 = Hmac; diff --git a/codex-rs/app-server/tests/suite/v2/dynamic_tools.rs b/codex-rs/app-server/tests/suite/v2/dynamic_tools.rs index 0ab3f472357..f908b4f0abf 100644 --- a/codex-rs/app-server/tests/suite/v2/dynamic_tools.rs +++ b/codex-rs/app-server/tests/suite/v2/dynamic_tools.rs @@ -34,7 +34,7 @@ use tempfile::TempDir; use tokio::time::timeout; use wiremock::MockServer; -const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(30); /// Ensures dynamic tool specs are serialized into the model request payload. #[tokio::test] diff --git a/codex-rs/app-server/tests/suite/v2/experimental_api.rs b/codex-rs/app-server/tests/suite/v2/experimental_api.rs index 2fd457faf23..fb57d3ac63c 100644 --- a/codex-rs/app-server/tests/suite/v2/experimental_api.rs +++ b/codex-rs/app-server/tests/suite/v2/experimental_api.rs @@ -24,7 +24,7 @@ use std::time::Duration; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); #[tokio::test] async fn mock_experimental_method_requires_experimental_api_capability() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs b/codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs index 3063830d5a0..07bdd0bde17 100644 --- a/codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs +++ b/codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs @@ -24,7 +24,7 @@ use std::collections::BTreeMap; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); #[tokio::test] async fn experimental_feature_list_returns_feature_metadata_with_stage() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/fs.rs b/codex-rs/app-server/tests/suite/v2/fs.rs index c7f28f09f55..be295ca41c9 100644 --- a/codex-rs/app-server/tests/suite/v2/fs.rs +++ b/codex-rs/app-server/tests/suite/v2/fs.rs @@ -27,7 +27,7 @@ use std::os::unix::fs::symlink; #[cfg(unix)] use std::process::Command; -const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(30); async fn initialized_mcp(codex_home: &TempDir) -> Result { let mut mcp = McpProcess::new(codex_home.path()).await?; diff --git a/codex-rs/app-server/tests/suite/v2/initialize.rs b/codex-rs/app-server/tests/suite/v2/initialize.rs index 165160468f7..6b01de63811 100644 --- a/codex-rs/app-server/tests/suite/v2/initialize.rs +++ b/codex-rs/app-server/tests/suite/v2/initialize.rs @@ -24,7 +24,7 @@ use std::time::Duration; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn initialize_uses_client_info_name_as_originator() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/marketplace_add.rs b/codex-rs/app-server/tests/suite/v2/marketplace_add.rs index cf3c57360ff..ef6b1803705 100644 --- a/codex-rs/app-server/tests/suite/v2/marketplace_add.rs +++ b/codex-rs/app-server/tests/suite/v2/marketplace_add.rs @@ -10,7 +10,7 @@ use tempfile::TempDir; use tokio::time::Duration; use tokio::time::timeout; -const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); #[tokio::test] async fn marketplace_add_local_directory_source() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/mcp_resource.rs b/codex-rs/app-server/tests/suite/v2/mcp_resource.rs index 0a38f3b37e9..331f00f9ea8 100644 --- a/codex-rs/app-server/tests/suite/v2/mcp_resource.rs +++ b/codex-rs/app-server/tests/suite/v2/mcp_resource.rs @@ -34,7 +34,7 @@ use tempfile::TempDir; use tokio::net::TcpListener; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(30); const TEST_RESOURCE_URI: &str = "test://codex/resource"; const TEST_BLOB_RESOURCE_URI: &str = "test://codex/resource.bin"; const TEST_RESOURCE_BLOB: &str = "YmluYXJ5LXJlc291cmNl"; diff --git a/codex-rs/app-server/tests/suite/v2/mcp_server_elicitation.rs b/codex-rs/app-server/tests/suite/v2/mcp_server_elicitation.rs index 13ebe0b99c8..ce56210e481 100644 --- a/codex-rs/app-server/tests/suite/v2/mcp_server_elicitation.rs +++ b/codex-rs/app-server/tests/suite/v2/mcp_server_elicitation.rs @@ -63,7 +63,7 @@ use tokio::net::TcpListener; use tokio::task::JoinHandle; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); const CONNECTOR_ID: &str = "calendar"; const CONNECTOR_NAME: &str = "Calendar"; const TOOL_NAMESPACE: &str = "mcp__codex_apps__calendar"; diff --git a/codex-rs/app-server/tests/suite/v2/mcp_server_status.rs b/codex-rs/app-server/tests/suite/v2/mcp_server_status.rs index 44efec4ed3f..c8fdbc81ff3 100644 --- a/codex-rs/app-server/tests/suite/v2/mcp_server_status.rs +++ b/codex-rs/app-server/tests/suite/v2/mcp_server_status.rs @@ -35,7 +35,7 @@ use tokio::net::TcpListener; use tokio::task::JoinHandle; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(30); #[tokio::test] async fn mcp_server_status_list_returns_raw_server_and_tool_names() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/mcp_tool.rs b/codex-rs/app-server/tests/suite/v2/mcp_tool.rs index 87556c83646..ee0920b07db 100644 --- a/codex-rs/app-server/tests/suite/v2/mcp_tool.rs +++ b/codex-rs/app-server/tests/suite/v2/mcp_tool.rs @@ -39,7 +39,7 @@ use tokio::net::TcpListener; use tokio::task::JoinHandle; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(30); const TEST_SERVER_NAME: &str = "tool_server"; const TEST_TOOL_NAME: &str = "echo_tool"; diff --git a/codex-rs/app-server/tests/suite/v2/memory_reset.rs b/codex-rs/app-server/tests/suite/v2/memory_reset.rs index 3c7ae38671d..2bf087e7ba6 100644 --- a/codex-rs/app-server/tests/suite/v2/memory_reset.rs +++ b/codex-rs/app-server/tests/suite/v2/memory_reset.rs @@ -17,7 +17,7 @@ use tempfile::TempDir; use tokio::time::timeout; use uuid::Uuid; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn memory_reset_clears_memory_files_and_rows_preserves_threads() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/model_list.rs b/codex-rs/app-server/tests/suite/v2/model_list.rs index 830ab0f783a..0bec6f67b5b 100644 --- a/codex-rs/app-server/tests/suite/v2/model_list.rs +++ b/codex-rs/app-server/tests/suite/v2/model_list.rs @@ -17,7 +17,7 @@ use pretty_assertions::assert_eq; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); const INVALID_REQUEST_ERROR_CODE: i64 = -32600; fn model_from_preset(preset: &ModelPreset) -> Model { diff --git a/codex-rs/app-server/tests/suite/v2/output_schema.rs b/codex-rs/app-server/tests/suite/v2/output_schema.rs index 149e098b686..e5354b2914c 100644 --- a/codex-rs/app-server/tests/suite/v2/output_schema.rs +++ b/codex-rs/app-server/tests/suite/v2/output_schema.rs @@ -15,7 +15,7 @@ use std::path::Path; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn turn_start_accepts_output_schema_v2() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/plan_item.rs b/codex-rs/app-server/tests/suite/v2/plan_item.rs index 97e67fa090c..7409c6ccfec 100644 --- a/codex-rs/app-server/tests/suite/v2/plan_item.rs +++ b/codex-rs/app-server/tests/suite/v2/plan_item.rs @@ -33,7 +33,7 @@ use tokio::time::sleep; use tokio::time::timeout; use wiremock::MockServer; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test(flavor = "multi_thread", worker_threads = 4)] async fn plan_mode_uses_proposed_plan_block_for_plan_item() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/plugin_install.rs b/codex-rs/app-server/tests/suite/v2/plugin_install.rs index a3bea531723..631f72be61c 100644 --- a/codex-rs/app-server/tests/suite/v2/plugin_install.rs +++ b/codex-rs/app-server/tests/suite/v2/plugin_install.rs @@ -51,7 +51,7 @@ use wiremock::matchers::header; use wiremock::matchers::method; use wiremock::matchers::path; -const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); #[tokio::test] async fn plugin_install_rejects_relative_marketplace_paths() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/plugin_list.rs b/codex-rs/app-server/tests/suite/v2/plugin_list.rs index 8bc4a8598ed..0c996d89f50 100644 --- a/codex-rs/app-server/tests/suite/v2/plugin_list.rs +++ b/codex-rs/app-server/tests/suite/v2/plugin_list.rs @@ -30,7 +30,7 @@ use wiremock::matchers::method; use wiremock::matchers::path; use wiremock::matchers::query_param; -const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); const TEST_CURATED_PLUGIN_SHA: &str = "0123456789abcdef0123456789abcdef01234567"; const STARTUP_REMOTE_PLUGIN_SYNC_MARKER_FILE: &str = ".tmp/app-server-remote-plugin-sync-v1"; @@ -733,10 +733,18 @@ async fn plugin_list_accepts_legacy_string_default_prompt() -> Result<()> { #[tokio::test] async fn plugin_list_force_remote_sync_returns_remote_sync_error_on_fail_open() -> Result<()> { let codex_home = TempDir::new()?; - write_plugin_sync_config(codex_home.path(), "https://chatgpt.com/backend-api/")?; + let server = MockServer::start().await; + write_plugin_sync_config(codex_home.path(), &format!("{}/backend-api/", server.uri()))?; write_openai_curated_marketplace(codex_home.path(), &["linear"])?; write_installed_plugin(&codex_home, "openai-curated", "linear")?; + Mock::given(method("GET")) + .and(path("/backend-api/plugins/featured")) + .and(query_param("platform", "codex")) + .respond_with(ResponseTemplate::new(200).set_body_string("[]")) + .mount(&server) + .await; + let mut mcp = McpProcess::new(codex_home.path()).await?; timeout(DEFAULT_TIMEOUT, mcp.initialize()).await??; diff --git a/codex-rs/app-server/tests/suite/v2/plugin_read.rs b/codex-rs/app-server/tests/suite/v2/plugin_read.rs index 115a04f0f54..995e296cb63 100644 --- a/codex-rs/app-server/tests/suite/v2/plugin_read.rs +++ b/codex-rs/app-server/tests/suite/v2/plugin_read.rs @@ -43,7 +43,7 @@ use tokio::net::TcpListener; use tokio::task::JoinHandle; use tokio::time::timeout; -const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); #[tokio::test] async fn plugin_read_returns_plugin_details_with_bundle_contents() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/plugin_uninstall.rs b/codex-rs/app-server/tests/suite/v2/plugin_uninstall.rs index 00fabe48321..3261a8774fe 100644 --- a/codex-rs/app-server/tests/suite/v2/plugin_uninstall.rs +++ b/codex-rs/app-server/tests/suite/v2/plugin_uninstall.rs @@ -23,7 +23,7 @@ use wiremock::matchers::header; use wiremock::matchers::method; use wiremock::matchers::path; -const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); #[tokio::test] async fn plugin_uninstall_removes_plugin_cache_and_config_entry() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/rate_limits.rs b/codex-rs/app-server/tests/suite/v2/rate_limits.rs index 203d664940a..c49b1120d79 100644 --- a/codex-rs/app-server/tests/suite/v2/rate_limits.rs +++ b/codex-rs/app-server/tests/suite/v2/rate_limits.rs @@ -24,7 +24,7 @@ use wiremock::matchers::header; use wiremock::matchers::method; use wiremock::matchers::path; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); const INVALID_REQUEST_ERROR_CODE: i64 = -32600; #[tokio::test] diff --git a/codex-rs/app-server/tests/suite/v2/realtime_conversation.rs b/codex-rs/app-server/tests/suite/v2/realtime_conversation.rs index 9870d410f17..70a5e558955 100644 --- a/codex-rs/app-server/tests/suite/v2/realtime_conversation.rs +++ b/codex-rs/app-server/tests/suite/v2/realtime_conversation.rs @@ -71,7 +71,7 @@ use wiremock::matchers::method; use wiremock::matchers::path; use wiremock::matchers::path_regex; -const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); const STARTUP_CONTEXT_HEADER: &str = "Startup context from Codex."; const V2_STEERING_ACKNOWLEDGEMENT: &str = "This was sent to steer the previous background agent task."; diff --git a/codex-rs/app-server/tests/suite/v2/request_permissions.rs b/codex-rs/app-server/tests/suite/v2/request_permissions.rs index 5a0679415d0..6ad12ac37b7 100644 --- a/codex-rs/app-server/tests/suite/v2/request_permissions.rs +++ b/codex-rs/app-server/tests/suite/v2/request_permissions.rs @@ -18,7 +18,7 @@ use codex_app_server_protocol::TurnStartResponse; use codex_app_server_protocol::UserInput as V2UserInput; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test(flavor = "multi_thread", worker_threads = 4)] async fn request_permissions_round_trip() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/request_user_input.rs b/codex-rs/app-server/tests/suite/v2/request_user_input.rs index f77ddfb4f7d..0d744412c0b 100644 --- a/codex-rs/app-server/tests/suite/v2/request_user_input.rs +++ b/codex-rs/app-server/tests/suite/v2/request_user_input.rs @@ -20,7 +20,7 @@ use codex_protocol::config_types::Settings; use codex_protocol::openai_models::ReasoningEffort; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test(flavor = "multi_thread", worker_threads = 4)] async fn request_user_input_round_trip() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/review.rs b/codex-rs/app-server/tests/suite/v2/review.rs index d56b9318e33..7dc5a484012 100644 --- a/codex-rs/app-server/tests/suite/v2/review.rs +++ b/codex-rs/app-server/tests/suite/v2/review.rs @@ -30,7 +30,7 @@ use serde_json::json; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); const INVALID_REQUEST_ERROR_CODE: i64 = -32600; #[tokio::test] diff --git a/codex-rs/app-server/tests/suite/v2/safety_check_downgrade.rs b/codex-rs/app-server/tests/suite/v2/safety_check_downgrade.rs index 8405d114905..9c9b31e7dfd 100644 --- a/codex-rs/app-server/tests/suite/v2/safety_check_downgrade.rs +++ b/codex-rs/app-server/tests/suite/v2/safety_check_downgrade.rs @@ -20,7 +20,7 @@ use pretty_assertions::assert_eq; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); const REQUESTED_MODEL: &str = "gpt-5.1-codex-max"; const SERVER_MODEL: &str = "gpt-5.2-codex"; diff --git a/codex-rs/app-server/tests/suite/v2/skills_list.rs b/codex-rs/app-server/tests/suite/v2/skills_list.rs index 8675b3a429b..16ade7b52d5 100644 --- a/codex-rs/app-server/tests/suite/v2/skills_list.rs +++ b/codex-rs/app-server/tests/suite/v2/skills_list.rs @@ -16,7 +16,7 @@ use pretty_assertions::assert_eq; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10); +const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); const WATCHER_TIMEOUT: Duration = Duration::from_secs(20); fn write_skill(root: &TempDir, name: &str) -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/thread_archive.rs b/codex-rs/app-server/tests/suite/v2/thread_archive.rs index 20fd6fd884f..85bdeca85e0 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_archive.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_archive.rs @@ -25,7 +25,7 @@ use std::path::Path; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn thread_archive_requires_materialized_rollout() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/thread_fork.rs b/codex-rs/app-server/tests/suite/v2/thread_fork.rs index 576a46d643d..fd6d2ee4742 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_fork.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_fork.rs @@ -43,7 +43,7 @@ use super::analytics::enable_analytics_capture; use super::analytics::thread_initialized_event; use super::analytics::wait_for_analytics_payload; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn thread_fork_creates_new_thread_and_emits_started() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/thread_inject_items.rs b/codex-rs/app-server/tests/suite/v2/thread_inject_items.rs index 56fd188c4b2..4c518ede94c 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_inject_items.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_inject_items.rs @@ -21,7 +21,7 @@ use std::path::Path; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn thread_inject_items_adds_raw_response_items_to_thread_history() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/thread_list.rs b/codex-rs/app-server/tests/suite/v2/thread_list.rs index 8fd4e473033..461a3eeef74 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_list.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_list.rs @@ -42,7 +42,7 @@ use tempfile::TempDir; use tokio::time::timeout; use uuid::Uuid; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); async fn init_mcp(codex_home: &Path) -> Result { let mut mcp = McpProcess::new(codex_home).await?; diff --git a/codex-rs/app-server/tests/suite/v2/thread_loaded_list.rs b/codex-rs/app-server/tests/suite/v2/thread_loaded_list.rs index 6cc298828dd..dd47e223e11 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_loaded_list.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_loaded_list.rs @@ -13,7 +13,7 @@ use std::path::Path; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn thread_loaded_list_returns_loaded_thread_ids() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/thread_memory_mode_set.rs b/codex-rs/app-server/tests/suite/v2/thread_memory_mode_set.rs index bf9bba7b2ff..d80b3fd9d0c 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_memory_mode_set.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_memory_mode_set.rs @@ -18,7 +18,7 @@ use std::sync::Arc; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn thread_memory_mode_set_updates_loaded_thread_state() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/thread_metadata_update.rs b/codex-rs/app-server/tests/suite/v2/thread_metadata_update.rs index 8bf9a8a9aa0..12de7e5737e 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_metadata_update.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_metadata_update.rs @@ -32,7 +32,7 @@ use std::sync::Arc; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn thread_metadata_update_patches_git_branch_and_returns_updated_thread() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/thread_read.rs b/codex-rs/app-server/tests/suite/v2/thread_read.rs index e4ff900150b..00a93957337 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_read.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_read.rs @@ -36,7 +36,7 @@ use std::path::Path; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn thread_read_returns_summary_without_turns() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/thread_resume.rs b/codex-rs/app-server/tests/suite/v2/thread_resume.rs index db3a0897fce..a457b46a104 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_resume.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_resume.rs @@ -76,7 +76,7 @@ use super::analytics::enable_analytics_capture; use super::analytics::thread_initialized_event; use super::analytics::wait_for_analytics_payload; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); const CODEX_5_2_INSTRUCTIONS_TEMPLATE_DEFAULT: &str = "You are Codex, a coding agent based on GPT-5. You and the user share the same workspace and collaborate to achieve the user's goals."; async fn wait_for_responses_request_count( diff --git a/codex-rs/app-server/tests/suite/v2/thread_rollback.rs b/codex-rs/app-server/tests/suite/v2/thread_rollback.rs index 3487b9e36af..45a8a9303e5 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_rollback.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_rollback.rs @@ -20,7 +20,7 @@ use serde_json::Value; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn thread_rollback_drops_last_turns_and_persists_to_rollout() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/thread_shell_command.rs b/codex-rs/app-server/tests/suite/v2/thread_shell_command.rs index f44beb9a293..fb88cdc6ca5 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_shell_command.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_shell_command.rs @@ -35,7 +35,7 @@ use std::path::Path; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn thread_shell_command_runs_as_standalone_turn_and_persists_history() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/thread_start.rs b/codex-rs/app-server/tests/suite/v2/thread_start.rs index b8d0db9a016..09496138d77 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_start.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_start.rs @@ -44,7 +44,7 @@ use super::analytics::mount_analytics_capture; use super::analytics::thread_initialized_event; use super::analytics::wait_for_analytics_payload; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn thread_start_creates_thread_and_emits_started() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/thread_status.rs b/codex-rs/app-server/tests/suite/v2/thread_status.rs index ad90e4900af..8997b861d3d 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_status.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_status.rs @@ -19,7 +19,7 @@ use codex_app_server_protocol::UserInput as V2UserInput; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test(flavor = "multi_thread", worker_threads = 4)] async fn thread_status_changed_emits_runtime_updates() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/thread_unsubscribe.rs b/codex-rs/app-server/tests/suite/v2/thread_unsubscribe.rs index 41ad4ecda62..1dee36ba384 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_unsubscribe.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_unsubscribe.rs @@ -30,7 +30,7 @@ use pretty_assertions::assert_eq; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); async fn wait_for_responses_request_count_to_stabilize( server: &wiremock::MockServer, diff --git a/codex-rs/app-server/tests/suite/v2/turn_interrupt.rs b/codex-rs/app-server/tests/suite/v2/turn_interrupt.rs index b5531377526..ab4fcfe7d5e 100644 --- a/codex-rs/app-server/tests/suite/v2/turn_interrupt.rs +++ b/codex-rs/app-server/tests/suite/v2/turn_interrupt.rs @@ -23,7 +23,7 @@ use codex_app_server_protocol::UserInput as V2UserInput; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn turn_interrupt_aborts_running_turn() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/turn_start.rs b/codex-rs/app-server/tests/suite/v2/turn_start.rs index e8682d7325b..0089aef1831 100644 --- a/codex-rs/app-server/tests/suite/v2/turn_start.rs +++ b/codex-rs/app-server/tests/suite/v2/turn_start.rs @@ -73,7 +73,7 @@ use super::analytics::wait_for_analytics_event; #[cfg(windows)] const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(25); #[cfg(not(windows))] -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); const TEST_ORIGINATOR: &str = "codex_vscode"; const LOCAL_PRAGMATIC_TEMPLATE: &str = "You are a deeply pragmatic, effective software engineer."; diff --git a/codex-rs/app-server/tests/suite/v2/turn_start_zsh_fork.rs b/codex-rs/app-server/tests/suite/v2/turn_start_zsh_fork.rs index eda24358ce9..3e4ef7ef506 100644 --- a/codex-rs/app-server/tests/suite/v2/turn_start_zsh_fork.rs +++ b/codex-rs/app-server/tests/suite/v2/turn_start_zsh_fork.rs @@ -43,7 +43,7 @@ use tokio::time::timeout; #[cfg(windows)] const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(15); #[cfg(not(windows))] -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn turn_start_shell_zsh_fork_executes_command_v2() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/turn_steer.rs b/codex-rs/app-server/tests/suite/v2/turn_steer.rs index 16e28d6cc5f..3016fb0d26e 100644 --- a/codex-rs/app-server/tests/suite/v2/turn_steer.rs +++ b/codex-rs/app-server/tests/suite/v2/turn_steer.rs @@ -27,7 +27,7 @@ use tokio::time::timeout; use super::analytics::enable_analytics_capture; use super::analytics::wait_for_analytics_event; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn turn_steer_requires_active_turn() -> Result<()> { diff --git a/codex-rs/app-server/tests/suite/v2/windows_sandbox_setup.rs b/codex-rs/app-server/tests/suite/v2/windows_sandbox_setup.rs index a0466a459be..56c93caf4bd 100644 --- a/codex-rs/app-server/tests/suite/v2/windows_sandbox_setup.rs +++ b/codex-rs/app-server/tests/suite/v2/windows_sandbox_setup.rs @@ -15,7 +15,7 @@ use std::collections::BTreeMap; use tempfile::TempDir; use tokio::time::timeout; -const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); #[tokio::test] async fn windows_sandbox_setup_start_emits_completion_notification() -> Result<()> { From 1068a41fcf2b8880c423f90d2c4bcb7a82b6d2b6 Mon Sep 17 00:00:00 2001 From: Joe Gershenson Date: Wed, 15 Apr 2026 13:20:34 -0700 Subject: [PATCH 13/13] Stabilize TUI memory mode state test --- codex-rs/tui/src/app.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index 13d1d368f5e..a46cbfa88c4 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -8154,6 +8154,16 @@ mod tests { let codex_home = tempdir()?; app.config.codex_home = codex_home.path().to_path_buf().abs(); app.config.sqlite_home = codex_home.path().to_path_buf(); + let state_db = codex_state::StateRuntime::init( + codex_home.path().to_path_buf(), + app.config.model_provider_id.clone(), + ) + .await + .expect("state db should initialize"); + state_db + .mark_backfill_complete(/*last_watermark*/ None) + .await + .expect("state db backfill should be marked complete"); let mut app_server = crate::start_embedded_app_server_for_picker(&app.config).await?; let started = app_server.start_thread(&app.config).await?; @@ -8167,12 +8177,6 @@ mod tests { ) .await; - let state_db = codex_state::StateRuntime::init( - codex_home.path().to_path_buf(), - app.config.model_provider_id.clone(), - ) - .await - .expect("state db should initialize"); let memory_mode = time::timeout(Duration::from_secs(10), async { loop { let memory_mode = state_db