mirror of
https://github.com/openai/codex.git
synced 2026-10-18 17:18:52 +00:00
Move the exec-server test fixture into shared test support (#52674)
## What changed Move `ExecServerProcess` into `core_test_support::exec_server` and update the sandbox, plugin, access, and turn-input tests to use it. Preserve the fixture's startup timeout, temporary `CODEX_HOME`, WebSocket URL discovery, and child-process cleanup. GitOrigin-RevId: 152de3a83f4ad39e2c1223e15438608dba452850
This commit is contained in:
committed by
copyberry
parent
04ad786998
commit
cb6f6141f8
@@ -0,0 +1,73 @@
|
||||
//! Shared native exec-server process fixture; dropping it stops the child process.
|
||||
|
||||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use anyhow::bail;
|
||||
use std::process::Stdio;
|
||||
use std::time::Duration;
|
||||
use tempfile::TempDir;
|
||||
use tokio::io::AsyncBufReadExt;
|
||||
use tokio::io::BufReader;
|
||||
use tokio::process::Child;
|
||||
use tokio::process::ChildStdout;
|
||||
use tokio::process::Command;
|
||||
use tokio::time::Instant;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const EXEC_SERVER_START_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
pub struct ExecServerProcess {
|
||||
_codex_home: TempDir,
|
||||
child: Child,
|
||||
_stdout: BufReader<ChildStdout>,
|
||||
pub websocket_url: String,
|
||||
}
|
||||
|
||||
impl ExecServerProcess {
|
||||
pub async fn start() -> Result<Self> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let mut child = Command::new(codex_utils_cargo_bin::cargo_bin("codex")?)
|
||||
.args(["exec-server", "--listen", "ws://127.0.0.1:0"])
|
||||
.env("CODEX_HOME", codex_home.path())
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::inherit())
|
||||
.kill_on_drop(true)
|
||||
.spawn()?;
|
||||
let stdout = child
|
||||
.stdout
|
||||
.take()
|
||||
.context("exec-server stdout should be piped")?;
|
||||
let mut stdout = BufReader::new(stdout);
|
||||
let deadline = Instant::now() + EXEC_SERVER_START_TIMEOUT;
|
||||
let websocket_url = loop {
|
||||
let remaining = deadline
|
||||
.checked_duration_since(Instant::now())
|
||||
.context("timed out waiting for exec-server listen URL")?;
|
||||
let mut line = String::new();
|
||||
let bytes_read = timeout(remaining, stdout.read_line(&mut line))
|
||||
.await
|
||||
.context("timed out reading exec-server listen URL")??;
|
||||
if bytes_read == 0 {
|
||||
bail!("exec-server exited before printing its listen URL");
|
||||
}
|
||||
let line = line.trim();
|
||||
if line.starts_with("ws://") {
|
||||
break line.to_string();
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
_codex_home: codex_home,
|
||||
child,
|
||||
_stdout: stdout,
|
||||
websocket_url,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ExecServerProcess {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.child.start_kill();
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ use std::path::PathBuf;
|
||||
|
||||
pub mod apps_test_server;
|
||||
pub mod context_snapshot;
|
||||
pub mod exec_server;
|
||||
pub mod hooks;
|
||||
pub mod process;
|
||||
pub mod responses;
|
||||
|
||||
@@ -59,7 +59,7 @@ async fn daybreak_metadata_follows_the_actual_plugin_call(case: AccessCase) -> R
|
||||
skip_if_no_network!(Ok(()));
|
||||
#[cfg(unix)]
|
||||
let remote = if matches!(case, AccessCase::RemoteStdio) {
|
||||
Some(super::multi_exec_server_sandbox::ExecServerProcess::start().await?)
|
||||
Some(core_test_support::exec_server::ExecServerProcess::start().await?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
use codex_core::TurnInputRequest;
|
||||
use codex_protocol::protocol::TurnEnvironmentRequests;
|
||||
use std::process::Stdio;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use anyhow::bail;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::permissions::NetworkSandboxPolicy;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
@@ -15,6 +13,7 @@ use codex_protocol::protocol::ThreadSettingsOverrides;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use codex_utils_path_uri::PathUri;
|
||||
use core_test_support::exec_server::ExecServerProcess;
|
||||
use core_test_support::responses::ev_assistant_message;
|
||||
use core_test_support::responses::ev_completed;
|
||||
use core_test_support::responses::ev_function_call;
|
||||
@@ -28,12 +27,6 @@ use core_test_support::wait_for_event_with_timeout;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::json;
|
||||
use tempfile::TempDir;
|
||||
use tokio::io::AsyncBufReadExt;
|
||||
use tokio::io::BufReader;
|
||||
use tokio::process::Child;
|
||||
use tokio::process::ChildStdout;
|
||||
use tokio::process::Command;
|
||||
use tokio::time::Instant;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const FIRST_ENVIRONMENT_ID: &str = "first";
|
||||
@@ -43,62 +36,6 @@ const SECOND_CALL_ID: &str = "write-from-second";
|
||||
const EXEC_SERVER_START_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
const TURN_COMPLETE_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
pub(super) struct ExecServerProcess {
|
||||
_codex_home: TempDir,
|
||||
child: Child,
|
||||
_stdout: BufReader<ChildStdout>,
|
||||
pub(super) websocket_url: String,
|
||||
}
|
||||
|
||||
impl ExecServerProcess {
|
||||
pub(super) async fn start() -> Result<Self> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let mut child = Command::new(codex_utils_cargo_bin::cargo_bin("codex")?)
|
||||
.args(["exec-server", "--listen", "ws://127.0.0.1:0"])
|
||||
.env("CODEX_HOME", codex_home.path())
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::inherit())
|
||||
.kill_on_drop(true)
|
||||
.spawn()?;
|
||||
let stdout = child
|
||||
.stdout
|
||||
.take()
|
||||
.context("exec-server stdout should be piped")?;
|
||||
let mut stdout = BufReader::new(stdout);
|
||||
let deadline = Instant::now() + EXEC_SERVER_START_TIMEOUT;
|
||||
let websocket_url = loop {
|
||||
let remaining = deadline
|
||||
.checked_duration_since(Instant::now())
|
||||
.context("timed out waiting for exec-server listen URL")?;
|
||||
let mut line = String::new();
|
||||
let bytes_read = timeout(remaining, stdout.read_line(&mut line))
|
||||
.await
|
||||
.context("timed out reading exec-server listen URL")??;
|
||||
if bytes_read == 0 {
|
||||
bail!("exec-server exited before printing its listen URL");
|
||||
}
|
||||
let line = line.trim();
|
||||
if line.starts_with("ws://") {
|
||||
break line.to_string();
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
_codex_home: codex_home,
|
||||
child,
|
||||
_stdout: stdout,
|
||||
websocket_url,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ExecServerProcess {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.child.start_kill();
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
async fn two_exec_servers_isolate_workspace_write_roots() -> Result<()> {
|
||||
let first_exec_server = ExecServerProcess::start().await?;
|
||||
|
||||
@@ -674,7 +674,7 @@ printf 'STDIN_OK\n'
|
||||
});
|
||||
// Exercise both native and executor-managed sandboxes with the same plugin fixture.
|
||||
let _executor = if environment_id == codex_exec_server::REMOTE_ENVIRONMENT_ID {
|
||||
let executor = super::multi_exec_server_sandbox::ExecServerProcess::start().await?;
|
||||
let executor = core_test_support::exec_server::ExecServerProcess::start().await?;
|
||||
builder = builder.with_exec_server_url(executor.websocket_url.clone());
|
||||
Some(executor)
|
||||
} else {
|
||||
@@ -732,7 +732,7 @@ async fn remote_plugin_measurements_require_the_frontend_version() -> Result<()>
|
||||
skip_if_no_network!(Ok(()));
|
||||
// This fixture needs a real remote transport with separately controlled frontend
|
||||
// and executor caches, rather than the runner's automatic executor selection.
|
||||
let executor = super::multi_exec_server_sandbox::ExecServerProcess::start().await?;
|
||||
let executor = core_test_support::exec_server::ExecServerProcess::start().await?;
|
||||
let server = start_mock_server().await;
|
||||
let home = Arc::new(TempDir::new()?);
|
||||
let frontend_script = write_remote_plugin_script_and_config(home.as_ref());
|
||||
|
||||
@@ -1465,7 +1465,7 @@ async fn sampling_is_ready_for_daemon_recovery(
|
||||
.await;
|
||||
#[cfg(unix)]
|
||||
let remote = if executor == "remote" {
|
||||
Some(super::multi_exec_server_sandbox::ExecServerProcess::start().await?)
|
||||
Some(core_test_support::exec_server::ExecServerProcess::start().await?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user