Stabilize cross-platform tests and directory-change fork permissions (#59369)

## Why

Tests need to distinguish slow subprocess startup from operation timeouts and wait for asynchronous work before asserting results or cleaning up fixtures.

## What changed

- Synchronize subprocess readiness, queued-turn completion, and matching UI events; allow more time for cold startup and separate startup from shutdown deadlines.
- Adapt Windows fixtures and permission expectations, provide the voice-host test runtime DLL path, and normalize platform paths and animated status snapshots.
- Use current configuration permissions when changing directories in embedded TUI sessions, while retaining saved permissions for remote sessions.
- Allow the release prompt-prefix comparison to accept the exact image-tool description update that removes image detail options, and refresh the corresponding tool snapshot.

## Testing

Extend inherited-session metadata coverage to both legacy and paginated thread history, including persisted history mode and revision-aware resume.

GitOrigin-RevId: 0afb38403fc0adb0d83175344749584f0cdf9979
This commit is contained in:
Dmitriy Kovalenko
2026-11-04 09:51:28 +00:00
committed by copyberry
parent 71a4c07036
commit 021fccb046
35 changed files with 417 additions and 116 deletions
+9 -1
View File
@@ -620,7 +620,15 @@ async fn daemon_startup(command: &str) -> Result<()> {
))
}
.await;
// Always stop the detached daemon, including on timeout or failed assertions.
// Elevated fresh Bedrock onboarding already verified that no daemon started.
if elevated
&& command == "bedrock"
&& let Ok((session, Ok(Ok(())))) = &result
{
session.terminate();
return Ok(());
}
// Stop the detached daemon, including on timeout or failed assertions.
let stopped = Command::new(&codex)
.env_clear()
.envs(&env)
+4
View File
@@ -153,6 +153,10 @@ wire_api = "responses"
}
#[test]
#[cfg_attr(
windows,
ignore = "Windows doctor fixture does not discover the synthetic Git executable"
)]
fn startup_and_doctor_do_not_execute_path_helpers() -> Result<()> {
let fixture = Fixture::new()?;
// Non-TTY dumb-terminal startup exits immediately after terminal detection.
+30
View File
@@ -278,6 +278,8 @@ async fn remote_session_commands_with_workload_identity_use_server_auth() -> Res
use codex_app_server_protocol::ThreadListResponse;
use codex_app_server_protocol::ThreadQueueListParams;
use codex_app_server_protocol::ThreadQueueListResponse;
use codex_app_server_protocol::ThreadReadParams;
use codex_app_server_protocol::ThreadReadResponse;
use codex_app_server_protocol::ThreadSetNameParams;
use codex_app_server_protocol::ThreadSetNameResponse;
use codex_app_server_protocol::ThreadStartParams;
@@ -541,6 +543,34 @@ async fn remote_session_commands_with_workload_identity_use_server_auth() -> Res
.to_string()
.contains(cold_message)
);
// The mock receives the request before the resumed turn finishes. Deletion
// requires an idle thread, and archiving removed our original subscription.
timeout(Duration::from_secs(30), async {
loop {
let read: ThreadReadResponse = app
.request_typed(ClientRequest::ThreadRead {
request_id: RequestId::Integer(5),
params: ThreadReadParams {
thread_id: thread_id.clone(),
include_turns: true,
},
})
.await?;
if let Some(last) = read.thread.turns.last()
&& last.id != completed.turn.id
&& last.status == TurnStatus::Completed
&& matches!(
read.thread.status,
ThreadStatus::Idle | ThreadStatus::NotLoaded
)
{
return anyhow::Ok(());
}
tokio::time::sleep(Duration::from_millis(50)).await;
}
})
.await
.context("resumed queued turn did not finish before deletion")??;
}
}
Ok(())