test: branch on target OS instead of runner flavor (#29712)

## Why

Core tests should branch on the executor's operating system, not on
runner details such as Docker or Wine. This keeps platform behavior
stable as new test backends are added and reserves Wine-specific skips
for actual runner debt.

## What

- Add `TestTargetOs` and target/host-aware skip helpers while keeping
`TestEnvironment` internal.
- Replace topology enum access with remote predicates and a narrow
Docker accessor.
- Migrate OS-semantic Wine skips, preserve runner-specific gaps, and
document the skip taxonomy.

## Validation

- `just test -p core_test_support`
- `just test -p codex-core
remote_test_env_can_connect_and_use_filesystem`
- `bazel test //codex-rs/core:core-all-wine-exec-test
--test_output=errors` reached test execution; unrelated existing
view-image, path, and timing failures remain.
- `just test -p codex-core` and `just test` reached broad test
execution; this checkout has unrelated helper, sandbox, and timing
failures.
This commit is contained in:
Adam Perry @ OpenAI
2026-06-23 14:27:13 -07:00
committed by GitHub
Unverified
parent 7b40e3523f
commit 9a79536e6b
19 changed files with 300 additions and 212 deletions
+9 -1
View File
@@ -11,7 +11,15 @@ Docker container is built and initialized via ./scripts/test-remote-env.sh
On x86-64 Linux, run Wine exec with
`bazel test //codex-rs/core:core-all-wine-exec-test --test_output=errors`.
Temporary blockers belong beside the test in `skip_if_wine_exec!` calls.
Local execution targets the host OS, Docker targets Linux, and Wine exec targets
Windows. Choose the skip macro by what the test depends on:
- `skip_if_target_windows!`: Windows target behavior.
- `skip_if_host_windows!`: Windows host constraints.
- `skip_if_remote!`: Local-only test behavior.
- `skip_if_no_remote_env!`: Remote-only test behavior.
- `skip_if_wine_exec!`: Wine-specific runner debt.
You can list devboxes via `applied_devbox ls`, pick the one with `codex` in the name.
Connect to devbox via `ssh <devbox_name>`.
@@ -25,7 +25,7 @@ use codex_app_server_protocol::UserInput as V2UserInput;
use codex_core::config::set_project_trust_level;
use codex_protocol::config_types::TrustLevel;
use codex_utils_absolute_path::AbsolutePathBuf;
use core_test_support::skip_if_windows;
use core_test_support::skip_if_host_windows;
use pretty_assertions::assert_eq;
use serde::Serialize;
use tempfile::TempDir;
@@ -651,7 +651,7 @@ async fn config_batch_write_toggles_user_hook() -> Result<()> {
#[tokio::test]
async fn config_batch_write_updates_hook_trust_for_loaded_session() -> Result<()> {
skip_if_windows!(Ok(()));
skip_if_host_windows!(Ok(()));
let responses = vec![
create_final_assistant_message_sse_response("Warmup")?,
@@ -902,7 +902,7 @@ command = "python3 {hook_script_path}"
#[tokio::test]
async fn config_batch_write_disables_hook_for_loaded_session() -> Result<()> {
skip_if_windows!(Ok(()));
skip_if_host_windows!(Ok(()));
let responses = vec![
create_final_assistant_message_sse_response("Warmup")?,
+10 -2
View File
@@ -5,8 +5,16 @@ This crate implements the business logic for Codex. It is designed to be used by
## Wine-exec integration tests
On x86-64 Linux, run the shared suite against the Windows exec server with
`bazel test //codex-rs/core:core-all-wine-exec-test`. Temporary blockers use a
source-local `skip_if_wine_exec!` call and reason.
`bazel test //codex-rs/core:core-all-wine-exec-test`.
Local execution targets the host OS, Docker targets Linux, and Wine exec targets
Windows. Choose the skip macro by what the test depends on:
- `skip_if_target_windows!`: Windows target behavior.
- `skip_if_host_windows!`: Windows host constraints.
- `skip_if_remote!`: Local-only test behavior.
- `skip_if_no_remote_env!`: Remote-only test behavior.
- `skip_if_wine_exec!`: Wine-specific runner debt.
## Dependencies
+3 -7
View File
@@ -23,7 +23,7 @@ use codex_sandboxing::SandboxType;
use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_output_truncation::TruncationPolicy;
use codex_utils_output_truncation::approx_token_count;
use core_test_support::get_remote_test_env;
use core_test_support::skip_if_no_remote_env;
use core_test_support::skip_if_sandbox;
use core_test_support::test_codex::test_env as remote_test_env;
use pretty_assertions::assert_eq;
@@ -836,9 +836,7 @@ async fn completed_pipe_commands_preserve_exit_code() -> anyhow::Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn unified_exec_uses_remote_exec_server_when_configured() -> anyhow::Result<()> {
skip_if_sandbox!(Ok(()));
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_no_remote_env!(Ok(()));
let remote_test_env = remote_test_env().await?;
let (_, turn) = make_session_and_context().await;
@@ -888,9 +886,7 @@ async fn unified_exec_uses_remote_exec_server_when_configured() -> anyhow::Resul
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn remote_exec_server_rejects_inherited_fd_launches() -> anyhow::Result<()> {
skip_if_sandbox!(Ok(()));
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_no_remote_env!(Ok(()));
let remote_test_env = remote_test_env().await?;
let (_, mut turn) = make_session_and_context().await;
+66 -21
View File
@@ -36,9 +36,15 @@ mod test_environment;
pub mod tracing;
pub mod zsh_fork;
pub use test_environment::TestEnvironment;
pub use test_environment::get_remote_test_env;
pub use test_environment::test_environment;
pub(crate) use test_environment::TestEnvironment;
pub use test_environment::TestTargetOs;
pub use test_environment::is_remote_test_environment;
#[doc(hidden)]
pub use test_environment::is_wine_exec_test_environment;
#[doc(hidden)]
pub use test_environment::test_docker_container_name;
pub(crate) use test_environment::test_environment;
pub use test_environment::test_target_os;
static TEST_ARG0_PATH_ENTRY: OnceLock<Option<Arg0PathEntryGuard>> = OnceLock::new();
@@ -574,21 +580,18 @@ macro_rules! skip_if_no_network {
}
// Exported so the public skip macros can expand in downstream test crates.
// Call `skip_if_remote!` or `skip_if_wine_exec!` instead.
#[macro_export]
#[doc(hidden)]
macro_rules! skip_if_test_environment {
($pattern:pat, $reason:expr $(,)?) => {{
let environment = $crate::test_environment();
if ::std::matches!(&environment, $pattern) {
eprintln!("Skipping test in {environment:?}: {}", $reason);
macro_rules! skip_if_test_condition {
($condition:expr, $environment:expr, $reason:expr $(,)?) => {{
if $condition {
eprintln!("Skipping test in {}: {}", $environment, $reason);
return;
}
}};
($return_value:expr, $pattern:pat, $reason:expr $(,)?) => {{
let environment = $crate::test_environment();
if ::std::matches!(&environment, $pattern) {
eprintln!("Skipping test in {environment:?}: {}", $reason);
($return_value:expr, $condition:expr, $environment:expr, $reason:expr $(,)?) => {{
if $condition {
eprintln!("Skipping test in {}: {}", $environment, $reason);
return $return_value;
}
}};
@@ -597,29 +600,71 @@ macro_rules! skip_if_test_environment {
#[macro_export]
macro_rules! skip_if_remote {
($reason:expr $(,)?) => {{
$crate::skip_if_test_environment!(
$crate::TestEnvironment::Docker { .. } | $crate::TestEnvironment::WineExec,
$crate::skip_if_test_condition!(
$crate::is_remote_test_environment(),
"a remote test environment",
$reason,
);
}};
($return_value:expr, $reason:expr $(,)?) => {{
$crate::skip_if_test_environment!(
$crate::skip_if_test_condition!(
$return_value,
$crate::TestEnvironment::Docker { .. } | $crate::TestEnvironment::WineExec,
$crate::is_remote_test_environment(),
"a remote test environment",
$reason,
);
}};
}
#[macro_export]
macro_rules! skip_if_no_remote_env {
() => {{
if !$crate::is_remote_test_environment() {
eprintln!("Skipping test because it requires a remote test environment.");
return;
}
}};
($return_value:expr $(,)?) => {{
if !$crate::is_remote_test_environment() {
eprintln!("Skipping test because it requires a remote test environment.");
return $return_value;
}
}};
}
#[macro_export]
macro_rules! skip_if_wine_exec {
($reason:expr $(,)?) => {{
$crate::skip_if_test_environment!($crate::TestEnvironment::WineExec, $reason);
$crate::skip_if_test_condition!(
$crate::is_wine_exec_test_environment(),
"the Wine-exec test environment",
$reason,
);
}};
($return_value:expr, $reason:expr $(,)?) => {{
$crate::skip_if_test_environment!(
$crate::skip_if_test_condition!(
$return_value,
$crate::TestEnvironment::WineExec,
$crate::is_wine_exec_test_environment(),
"the Wine-exec test environment",
$reason,
);
}};
}
#[macro_export]
macro_rules! skip_if_target_windows {
($reason:expr $(,)?) => {{
$crate::skip_if_test_condition!(
$crate::test_target_os() == $crate::TestTargetOs::Windows,
"a Windows target environment",
$reason,
);
}};
($return_value:expr, $reason:expr $(,)?) => {{
$crate::skip_if_test_condition!(
$return_value,
$crate::test_target_os() == $crate::TestTargetOs::Windows,
"a Windows target environment",
$reason,
);
}};
@@ -662,7 +707,7 @@ macro_rules! codex_linux_sandbox_exe_or_skip {
}
#[macro_export]
macro_rules! skip_if_windows {
macro_rules! skip_if_host_windows {
($return_value:expr $(,)?) => {{
if cfg!(target_os = "windows") {
println!("Skipping test because it cannot execute on Windows.");
+4 -4
View File
@@ -59,13 +59,13 @@ use wiremock::MockServer;
use crate::TempDirExt;
use crate::TestEnvironment;
use crate::get_remote_test_env;
use crate::load_default_config_for_test;
use crate::load_default_config_for_test_with_cloud_config_bundle;
use crate::responses::WebSocketTestServer;
use crate::responses::output_value_to_text;
use crate::responses::start_mock_server;
use crate::streaming_sse::StreamingSseServer;
use crate::test_environment;
use crate::wait_for_event_match;
use crate::wait_for_event_with_timeout;
use wiremock::Match;
@@ -163,8 +163,8 @@ impl Drop for TestEnv {
}
pub async fn test_env() -> Result<TestEnv> {
match get_remote_test_env() {
Some(remote_env) => {
match test_environment() {
remote_env @ (TestEnvironment::Docker { .. } | TestEnvironment::WineExec) => {
let websocket_url = remote_exec_server_url()?;
let environment =
codex_exec_server::Environment::create_for_tests(Some(websocket_url.clone()))?;
@@ -202,7 +202,7 @@ pub async fn test_env() -> Result<TestEnv> {
remote_container_name: remote_env.docker_container_name().map(str::to_owned),
})
}
None => TestEnv::local().await,
TestEnvironment::Local => TestEnv::local().await,
}
}
+64 -12
View File
@@ -9,25 +9,61 @@ pub const TEST_ENVIRONMENT_ENV_VAR: &str = "CODEX_TEST_ENVIRONMENT";
pub const LEGACY_REMOTE_ENV_ENV_VAR: &str = "CODEX_TEST_REMOTE_ENV";
pub const DOCKER_CONTAINER_ENV_VAR: &str = "CODEX_TEST_REMOTE_ENV_CONTAINER_NAME";
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TestTargetOs {
Linux,
MacOs,
Windows,
}
impl TestTargetOs {
const fn host() -> Self {
if cfg!(target_os = "macos") {
Self::MacOs
} else if cfg!(target_os = "windows") {
Self::Windows
} else if cfg!(target_os = "linux") {
Self::Linux
} else {
unreachable!()
}
}
const fn path_convention(self) -> PathConvention {
match self {
Self::Linux | Self::MacOs => PathConvention::Posix,
Self::Windows => PathConvention::Windows,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum TestEnvironment {
pub(crate) enum TestEnvironment {
Local,
Docker { container_name: String },
WineExec,
}
impl TestEnvironment {
pub fn is_remote(&self) -> bool {
pub(crate) fn is_remote(&self) -> bool {
!matches!(self, Self::Local)
}
pub fn docker_container_name(&self) -> Option<&str> {
pub(crate) fn docker_container_name(&self) -> Option<&str> {
match self {
Self::Docker { container_name } => Some(container_name),
Self::Local | Self::WineExec => None,
}
}
pub(crate) const fn target_os(&self) -> TestTargetOs {
match self {
Self::Local => TestTargetOs::host(),
Self::Docker { .. } => TestTargetOs::Linux,
Self::WineExec => TestTargetOs::Windows,
}
}
pub(crate) fn remote_cwd(&self, instance_id: &str) -> Result<Option<LegacyAppPathString>> {
let path_uri = match self {
Self::Local => return Ok(None),
@@ -47,15 +83,11 @@ impl TestEnvironment {
}
pub(crate) fn path_convention(&self) -> PathConvention {
match self {
Self::Local => PathConvention::native(),
Self::Docker { .. } => PathConvention::Posix,
Self::WineExec => PathConvention::Windows,
}
self.target_os().path_convention()
}
}
pub fn test_environment() -> TestEnvironment {
pub(crate) fn test_environment() -> TestEnvironment {
let environment = parse_test_environment(
std::env::var_os(TEST_ENVIRONMENT_ENV_VAR).as_deref(),
std::env::var_os(LEGACY_REMOTE_ENV_ENV_VAR).as_deref(),
@@ -70,9 +102,29 @@ pub fn test_environment() -> TestEnvironment {
environment
}
pub fn get_remote_test_env() -> Option<TestEnvironment> {
let environment = test_environment();
environment.is_remote().then_some(environment)
/// Returns the operating system used by the selected test execution environment.
pub fn test_target_os() -> TestTargetOs {
test_environment().target_os()
}
/// Returns whether the selected test execution environment is remote.
pub fn is_remote_test_environment() -> bool {
test_environment().is_remote()
}
/// Returns the selected Docker test container, when the harness requires direct access to it.
#[doc(hidden)]
pub fn test_docker_container_name() -> Option<String> {
match test_environment() {
TestEnvironment::Docker { container_name } => Some(container_name),
TestEnvironment::Local | TestEnvironment::WineExec => None,
}
}
/// Returns whether the Wine-backed executor is selected.
#[doc(hidden)]
pub fn is_wine_exec_test_environment() -> bool {
matches!(test_environment(), TestEnvironment::WineExec)
}
fn parse_test_environment(
@@ -116,3 +116,30 @@ fn rejects_invalid_or_incomplete_configuration() {
))
);
}
#[test]
fn derives_target_operating_system_and_placement() {
#[cfg(target_os = "linux")]
let expected_local_target_os = TestTargetOs::Linux;
#[cfg(target_os = "macos")]
let expected_local_target_os = TestTargetOs::MacOs;
#[cfg(target_os = "windows")]
let expected_local_target_os = TestTargetOs::Windows;
let environments = [
TestEnvironment::Local,
TestEnvironment::Docker {
container_name: "container-1".to_string(),
},
TestEnvironment::WineExec,
];
assert_eq!(
environments.map(|environment| (environment.target_os(), environment.is_remote())),
[
(expected_local_target_os, false),
(TestTargetOs::Linux, true),
(TestTargetOs::Windows, true),
]
);
}
+2 -4
View File
@@ -16,7 +16,6 @@ use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_path_uri::PathUri;
use core_test_support::PathBufExt;
use core_test_support::create_directory_symlink;
use core_test_support::get_remote_test_env;
use core_test_support::load_default_config_for_test;
use core_test_support::responses;
use core_test_support::responses::ev_completed;
@@ -25,6 +24,7 @@ use core_test_support::responses::mount_sse_once;
use core_test_support::responses::sse;
use core_test_support::responses::start_mock_server;
use core_test_support::skip_if_no_network;
use core_test_support::skip_if_no_remote_env;
use core_test_support::test_codex::RecordingUserInstructionsProvider;
use core_test_support::test_codex::TestCodexBuilder;
use core_test_support::test_codex::test_codex;
@@ -597,9 +597,7 @@ async fn fresh_thread_composes_global_before_project_and_reports_sources() -> Re
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn multi_environment_thread_loads_every_project_and_keeps_creation_snapshot() -> Result<()> {
skip_if_no_network!(Ok(()));
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_no_remote_env!(Ok(()));
let server = responses::start_mock_server().await;
let response_mock = responses::mount_sse_sequence(
+5 -7
View File
@@ -38,7 +38,6 @@ use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_path_uri::PathUri;
use core_test_support::PathBufExt;
use core_test_support::assert_regex_match;
use core_test_support::get_remote_test_env;
use core_test_support::responses::ev_assistant_message;
use core_test_support::responses::ev_completed;
use core_test_support::responses::ev_function_call;
@@ -48,8 +47,9 @@ use core_test_support::responses::mount_sse_sequence;
use core_test_support::responses::sse;
use core_test_support::responses::start_mock_server;
use core_test_support::skip_if_no_network;
use core_test_support::skip_if_no_remote_env;
use core_test_support::skip_if_remote;
use core_test_support::skip_if_wine_exec;
use core_test_support::skip_if_target_windows;
use core_test_support::test_codex::TestCodexBuilder;
use core_test_support::test_codex::TestCodexHarness;
use core_test_support::test_codex::local;
@@ -911,7 +911,7 @@ async fn apply_patch_cli_preserves_existing_hard_link_outside_workspace() -> Res
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn apply_patch_cli_rejects_move_path_traversal_outside_workspace() -> Result<()> {
// TODO(anp): Remove after apply-patch fixtures use target-native paths.
skip_if_wine_exec!(Ok(()), "asserts POSIX workspace traversal behavior");
skip_if_target_windows!(Ok(()), "asserts POSIX workspace traversal behavior");
skip_if_no_network!(Ok(()));
let harness = apply_patch_harness().await?;
@@ -1568,14 +1568,12 @@ async fn apply_patch_emits_turn_diff_event_with_unified_diff() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn apply_patch_turn_diff_tracks_local_and_remote_environment_paths() -> Result<()> {
// TODO(anp): Remove after shared-cwd helpers use target-native paths.
skip_if_wine_exec!(
skip_if_target_windows!(
Ok(()),
"requires a cwd valid in local POSIX and remote Windows environments"
);
skip_if_no_network!(Ok(()));
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_no_remote_env!(Ok(()));
let server = start_mock_server().await;
let mut builder = test_codex();
+2 -2
View File
@@ -38,8 +38,8 @@ use core_test_support::responses::mount_sse_once;
use core_test_support::responses::mount_sse_sequence;
use core_test_support::responses::sse;
use core_test_support::responses::start_mock_server;
use core_test_support::skip_if_host_windows;
use core_test_support::skip_if_no_network;
use core_test_support::skip_if_windows;
use core_test_support::streaming_sse::StreamingSseChunk;
use core_test_support::streaming_sse::start_streaming_sse_server;
use core_test_support::test_codex::test_codex;
@@ -4012,7 +4012,7 @@ async fn post_tool_use_spills_large_feedback_message() -> Result<()> {
#[tokio::test]
async fn post_tool_use_blocks_when_exec_session_completes_via_write_stdin() -> Result<()> {
skip_if_no_network!(Ok(()));
skip_if_windows!(Ok(()));
skip_if_host_windows!(Ok(()));
let server = start_mock_server().await;
let start_call_id = "posttooluse-exec-session-start";
@@ -22,7 +22,6 @@ use codex_protocol::user_input::UserInput;
use codex_utils_path_uri::PathUri;
use core_test_support::PathBufExt;
use core_test_support::PathExt;
use core_test_support::get_remote_test_env;
use core_test_support::managed_network_requirements_loader;
use core_test_support::responses::ResponseMock;
use core_test_support::responses::ev_assistant_message;
@@ -32,10 +31,11 @@ use core_test_support::responses::ev_response_created;
use core_test_support::responses::mount_sse_sequence;
use core_test_support::responses::sse;
use core_test_support::responses::start_mock_server;
use core_test_support::skip_if_host_windows;
use core_test_support::skip_if_no_network;
use core_test_support::skip_if_no_remote_env;
use core_test_support::skip_if_sandbox;
use core_test_support::skip_if_windows;
use core_test_support::skip_if_wine_exec;
use core_test_support::skip_if_target_windows;
use core_test_support::test_codex::TestCodex;
use core_test_support::test_codex::local;
use core_test_support::test_codex::test_codex;
@@ -58,13 +58,11 @@ const NETWORK_TEST_TARGET: &str = "http://codex-network-test.invalid:80";
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn approved_network_host_for_one_environment_still_prompts_in_another() -> Result<()> {
skip_if_wine_exec!(Ok(()), "uses the POSIX/Python network fixture");
skip_if_target_windows!(Ok(()), "uses the POSIX/Python network fixture");
skip_if_host_windows!(Ok(()));
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_no_remote_env!(Ok(()));
let server = start_mock_server().await;
let test = managed_network_unified_exec_test(&server).await?;
+39 -61
View File
@@ -34,8 +34,7 @@ use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_path_uri::PathUri;
use core_test_support::PathBufExt;
use core_test_support::PathExt;
use core_test_support::TestEnvironment;
use core_test_support::get_remote_test_env;
use core_test_support::TestTargetOs;
use core_test_support::responses::ev_apply_patch_custom_tool_call;
use core_test_support::responses::ev_assistant_message;
use core_test_support::responses::ev_completed;
@@ -47,11 +46,14 @@ use core_test_support::responses::mount_sse_sequence;
use core_test_support::responses::sse;
use core_test_support::responses::start_mock_server;
use core_test_support::skip_if_no_network;
use core_test_support::skip_if_wine_exec;
use core_test_support::skip_if_no_remote_env;
use core_test_support::skip_if_target_windows;
use core_test_support::test_codex::TestCodex;
use core_test_support::test_codex::local;
use core_test_support::test_codex::test_codex;
use core_test_support::test_codex::test_env;
use core_test_support::test_docker_container_name;
use core_test_support::test_target_os;
use core_test_support::wait_for_event;
use core_test_support::wait_for_event_match;
use futures::SinkExt;
@@ -167,9 +169,7 @@ async fn wait_for_completion_without_patch_approval(test: &TestCodex) {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn remote_test_env_can_connect_and_use_filesystem() -> Result<()> {
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_no_remote_env!(Ok(()));
let test_env = test_env().await?;
let file_system = test_env.environment().get_filesystem();
@@ -202,9 +202,7 @@ async fn remote_test_env_can_connect_and_use_filesystem() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn remote_test_env_exposes_target_shell_to_model() -> Result<()> {
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_no_remote_env!(Ok(()));
let server = start_mock_server().await;
let response_mock = mount_sse_once(
@@ -228,10 +226,10 @@ async fn remote_test_env_exposes_target_shell_to_model() -> Result<()> {
.context("environment context should be model visible")?;
// TODO(anp): Assert Wine-exec exposes a `C:\\...` cwd after model-visible paths preserve
// target-native spelling instead of the Linux orchestrator's `/C:/...` representation.
let expected_shell = match core_test_support::test_environment() {
TestEnvironment::Docker { .. } => "<shell>bash</shell>",
TestEnvironment::WineExec => "<shell>powershell</shell>",
TestEnvironment::Local => unreachable!("test requires a remote environment"),
let expected_shell = match test_target_os() {
TestTargetOs::Linux => "<shell>bash</shell>",
TestTargetOs::Windows => "<shell>powershell</shell>",
TestTargetOs::MacOs => unreachable!("remote test targets do not run macOS"),
};
assert_eq!(
environment_context
@@ -248,16 +246,18 @@ async fn remote_test_env_exposes_target_shell_to_model() -> Result<()> {
async fn explicit_remote_shell_runs_in_remote_cwd() -> Result<()> {
const CALL_ID: &str = "remote-explicit-shell";
let (shell, command) = match core_test_support::test_environment() {
TestEnvironment::Docker { .. } => (
skip_if_no_remote_env!(Ok(()));
let (shell, command) = match test_target_os() {
TestTargetOs::Linux => (
"bash",
r#"case "$PWD" in /tmp/codex-core-test-cwd-*) ;; *) echo "unexpected cwd: $PWD" >&2; exit 1 ;; esac"#,
),
TestEnvironment::WineExec => (
TestTargetOs::Windows => (
"powershell",
r#"$cwd = (Get-Location).Path; if ($cwd -notlike 'C:\codex-core-test-cwd-*') { Write-Error "unexpected cwd: $cwd"; exit 1 }"#,
),
TestEnvironment::Local => return Ok(()),
TestTargetOs::MacOs => unreachable!("remote test targets do not run macOS"),
};
let server = start_mock_server().await;
@@ -771,12 +771,10 @@ fn assert_normalized_path_rejected(error: &std::io::Error) {
}
fn remote_exec(script: &str) -> Result<()> {
let remote_env = get_remote_test_env().context("remote env should be configured")?;
let container_name = remote_env
.docker_container_name()
let container_name = test_docker_container_name()
.context("test requires direct access to the Docker container")?;
let output = Command::new("docker")
.args(["exec", container_name, "sh", "-lc", script])
.args(["exec", container_name.as_str(), "sh", "-lc", script])
.output()?;
assert!(
output.status.success(),
@@ -823,10 +821,8 @@ async fn exec_command_routing_output(
async fn exec_command_routes_to_selected_remote_environment() -> Result<()> {
skip_if_no_network!(Ok(()));
// TODO(anp): Remove after remote path fixtures use target-native paths.
skip_if_wine_exec!(Ok(()), "requires the Docker-backed POSIX executor");
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_target_windows!(Ok(()), "requires the Docker-backed POSIX executor");
skip_if_no_remote_env!(Ok(()));
let server = start_mock_server().await;
let test = unified_exec_test(&server).await?;
@@ -900,10 +896,8 @@ async fn exec_command_routes_to_selected_remote_environment() -> Result<()> {
async fn remote_request_permissions_grant_unblocks_later_remote_exec() -> Result<()> {
skip_if_no_network!(Ok(()));
// TODO(anp): Remove after remote path fixtures use target-native paths.
skip_if_wine_exec!(Ok(()), "requires the Docker-backed POSIX executor");
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_target_windows!(Ok(()), "requires the Docker-backed POSIX executor");
skip_if_no_remote_env!(Ok(()));
let server = start_mock_server().await;
let mut builder = test_codex().with_config(|config| {
@@ -1107,10 +1101,8 @@ async fn remote_request_permissions_grant_unblocks_later_remote_exec() -> Result
async fn apply_patch_freeform_routes_to_selected_remote_environment() -> Result<()> {
skip_if_no_network!(Ok(()));
// TODO(anp): Remove after remote path fixtures use target-native paths.
skip_if_wine_exec!(Ok(()), "requires the Docker-backed POSIX executor");
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_target_windows!(Ok(()), "requires the Docker-backed POSIX executor");
skip_if_no_remote_env!(Ok(()));
let server = start_mock_server().await;
let mut builder = test_codex();
@@ -1195,10 +1187,8 @@ async fn apply_patch_freeform_routes_to_selected_remote_environment() -> Result<
async fn apply_patch_approvals_are_remembered_per_environment() -> Result<()> {
skip_if_no_network!(Ok(()));
// TODO(anp): Remove after remote path fixtures use target-native paths.
skip_if_wine_exec!(Ok(()), "requires the Docker-backed POSIX executor");
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_target_windows!(Ok(()), "requires the Docker-backed POSIX executor");
skip_if_no_remote_env!(Ok(()));
let server = start_mock_server().await;
let mut builder = test_codex().with_config(|config| {
@@ -1386,10 +1376,8 @@ async fn apply_patch_intercepted_exec_command_routes_to_selected_remote_environm
{
skip_if_no_network!(Ok(()));
// TODO(anp): Remove after remote path fixtures use target-native paths.
skip_if_wine_exec!(Ok(()), "requires the Docker-backed POSIX executor");
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_target_windows!(Ok(()), "requires the Docker-backed POSIX executor");
skip_if_no_remote_env!(Ok(()));
let server = start_mock_server().await;
let test = unified_exec_test(&server).await?;
@@ -1482,11 +1470,9 @@ async fn apply_patch_intercepted_exec_command_routes_to_selected_remote_environm
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn remote_test_env_sandboxed_read_allows_readable_root() -> Result<()> {
// TODO(anp): Remove after remote sandbox fixtures use target-native paths.
skip_if_wine_exec!(Ok(()), "requires the Docker-backed POSIX executor");
skip_if_target_windows!(Ok(()), "requires the Docker-backed POSIX executor");
skip_if_no_network!(Ok(()));
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_no_remote_env!(Ok(()));
let test_env = test_env().await?;
let file_system = test_env.environment().get_filesystem();
@@ -1532,11 +1518,9 @@ async fn remote_test_env_sandboxed_read_allows_readable_root() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn remote_test_env_sandboxed_read_rejects_symlink_parent_dotdot_escape() -> Result<()> {
skip_if_wine_exec!(Ok(()), "tests POSIX symlink and parent traversal semantics");
skip_if_target_windows!(Ok(()), "tests POSIX symlink and parent traversal semantics");
skip_if_no_network!(Ok(()));
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_no_remote_env!(Ok(()));
let test_env = test_env().await?;
let file_system = test_env.environment().get_filesystem();
@@ -1568,11 +1552,9 @@ async fn remote_test_env_sandboxed_read_rejects_symlink_parent_dotdot_escape() -
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn remote_test_env_remove_removes_symlink_not_target() -> Result<()> {
skip_if_wine_exec!(Ok(()), "tests POSIX symlink removal semantics");
skip_if_target_windows!(Ok(()), "tests POSIX symlink removal semantics");
skip_if_no_network!(Ok(()));
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_no_remote_env!(Ok(()));
let test_env = test_env().await?;
let file_system = test_env.environment().get_filesystem();
@@ -1642,11 +1624,9 @@ async fn remote_test_env_remove_removes_symlink_not_target() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn remote_test_env_copy_preserves_symlink_source() -> Result<()> {
skip_if_wine_exec!(Ok(()), "tests POSIX symlink copy semantics");
skip_if_target_windows!(Ok(()), "tests POSIX symlink copy semantics");
skip_if_no_network!(Ok(()));
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_no_remote_env!(Ok(()));
let test_env = test_env().await?;
let file_system = test_env.environment().get_filesystem();
@@ -1678,14 +1658,12 @@ async fn remote_test_env_copy_preserves_symlink_source() -> Result<()> {
)
.await?;
let remote_env = get_remote_test_env().context("remote env should be configured")?;
let container_name = remote_env
.docker_container_name()
let container_name = test_docker_container_name()
.context("test requires direct access to the Docker container")?;
let link_target = Command::new("docker")
.args([
"exec",
container_name,
container_name.as_str(),
"readlink",
copied_symlink
.to_str()
+10 -12
View File
@@ -48,17 +48,19 @@ use codex_protocol::user_input::UserInput;
use codex_utils_cargo_bin::cargo_bin;
use codex_utils_path_uri::PathUri;
use core_test_support::assert_regex_match;
use core_test_support::is_remote_test_environment;
use core_test_support::responses;
use core_test_support::responses::mount_models_once;
use core_test_support::responses::mount_sse_once;
use core_test_support::responses::start_mock_server;
use core_test_support::skip_if_no_network;
use core_test_support::skip_if_no_remote_env;
use core_test_support::skip_if_wine_exec;
use core_test_support::stdio_server_bin;
use core_test_support::test_codex::TestCodex;
use core_test_support::test_codex::test_codex;
use core_test_support::test_codex::turn_permission_fields;
use core_test_support::test_environment;
use core_test_support::test_docker_container_name;
use core_test_support::wait_for_event;
use core_test_support::wait_for_mcp_server;
use image::DynamicImage;
@@ -165,7 +167,7 @@ enum McpCallEvent {
const REMOTE_MCP_ENVIRONMENT: &str = "remote";
fn remote_aware_environment_id() -> String {
if test_environment().is_remote() {
if is_remote_test_environment() {
REMOTE_MCP_ENVIRONMENT.to_string()
} else {
codex_config::DEFAULT_MCP_SERVER_ENVIRONMENT_ID.to_string()
@@ -181,8 +183,7 @@ fn remote_aware_environment_id() -> String {
/// container and return that in-container path instead.
fn remote_aware_stdio_server_bin() -> anyhow::Result<String> {
let bin = stdio_server_bin()?;
let environment = test_environment();
let Some(container_name) = environment.docker_container_name() else {
let Some(container_name) = test_docker_container_name() else {
return Ok(bin);
};
@@ -195,7 +196,7 @@ fn remote_aware_stdio_server_bin() -> anyhow::Result<String> {
// path instead of the host build artifact path.
// Several remote-aware MCP tests can run in parallel; give each copied
// binary its own path so one test cannot replace another test's executable.
copy_binary_to_remote_env(container_name, Path::new(&bin), "test_stdio_server")
copy_binary_to_remote_env(&container_name, Path::new(&bin), "test_stdio_server")
}
/// Builds a collision-resistant in-container path for copied test binaries.
@@ -506,7 +507,7 @@ fn assert_cwd_tool_output(structured: &Value, expected_cwd: &Path) {
.and_then(Value::as_str)
.expect("cwd tool should return a string cwd");
if test_environment().is_remote() {
if is_remote_test_environment() {
assert_eq!(
structured,
&json!({
@@ -1986,9 +1987,7 @@ async fn remote_stdio_env_var_source_does_not_copy_local_env() -> anyhow::Result
"requires a Windows test_stdio_server in the Wine-exec environment"
);
skip_if_no_network!(Ok(()));
if !test_environment().is_remote() {
return Ok(());
}
skip_if_no_remote_env!(Ok(()));
let server = responses::start_mock_server().await;
let call_id = "call-remote-source";
@@ -2501,11 +2500,10 @@ async fn start_streamable_http_test_server(
}
};
let environment = test_environment();
if let Some(container_name) = environment.docker_container_name() {
if let Some(container_name) = test_docker_container_name() {
return Ok(Some(
start_remote_streamable_http_test_server(
container_name,
&container_name,
&rmcp_http_server_bin,
expected_env_value,
expected_token,
+3 -3
View File
@@ -8,8 +8,8 @@ use core_test_support::responses::ev_function_call;
use core_test_support::responses::ev_response_created;
use core_test_support::responses::mount_sse_sequence;
use core_test_support::responses::sse;
use core_test_support::skip_if_host_windows;
use core_test_support::skip_if_no_network;
use core_test_support::skip_if_windows;
use core_test_support::test_codex::TestCodexBuilder;
use core_test_support::test_codex::TestCodexHarness;
use core_test_support::test_codex::test_codex;
@@ -181,7 +181,7 @@ async fn multi_line_output_with_login() -> anyhow::Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn pipe_output_with_login() -> anyhow::Result<()> {
skip_if_no_network!(Ok(()));
skip_if_windows!(Ok(()));
skip_if_host_windows!(Ok(()));
let harness = shell_command_harness_with(|builder| builder.with_model("gpt-5.4")).await?;
@@ -204,7 +204,7 @@ async fn pipe_output_with_login() -> anyhow::Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn pipe_output_without_login() -> anyhow::Result<()> {
skip_if_no_network!(Ok(()));
skip_if_windows!(Ok(()));
skip_if_host_windows!(Ok(()));
let harness = shell_command_harness_with(|builder| builder.with_model("gpt-5.4")).await?;
@@ -11,7 +11,7 @@ use core_test_support::responses::mount_sse_sequence;
use core_test_support::responses::sse;
use core_test_support::responses::start_mock_server;
use core_test_support::skip_if_no_network;
use core_test_support::skip_if_wine_exec;
use core_test_support::skip_if_target_windows;
use core_test_support::test_codex::test_codex;
use pretty_assertions::assert_eq;
use regex_lite::Regex;
@@ -236,7 +236,7 @@ M {file_name}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn apply_patch_custom_tool_call_reports_failure_output() -> Result<()> {
// TODO(anp): Remove after apply-patch assertions use target-native paths.
skip_if_wine_exec!(Ok(()), "asserts POSIX apply_patch failure text");
skip_if_target_windows!(Ok(()), "asserts POSIX apply_patch failure text");
skip_if_no_network!(Ok(()));
let harness = apply_patch_harness().await?;
+2 -2
View File
@@ -17,7 +17,7 @@ use core_test_support::responses::mount_sse_once;
use core_test_support::responses::sse;
use core_test_support::responses::start_mock_server;
use core_test_support::skip_if_no_network;
use core_test_support::skip_if_wine_exec;
use core_test_support::skip_if_target_windows;
use core_test_support::test_codex::local_selections;
use core_test_support::test_codex::test_codex;
use core_test_support::test_codex::turn_permission_fields;
@@ -49,7 +49,7 @@ async fn write_repo_skill(
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn user_turn_includes_skill_instructions() -> Result<()> {
// TODO(anp): Remove after skill-path helpers use target-native paths.
skip_if_wine_exec!(Ok(()), "requires native cross-OS skill paths");
skip_if_target_windows!(Ok(()), "requires native cross-OS skill paths");
skip_if_no_network!(Ok(()));
let server = start_mock_server().await;
+34 -55
View File
@@ -31,9 +31,10 @@ use core_test_support::responses::ev_response_created;
use core_test_support::responses::mount_sse_sequence;
use core_test_support::responses::sse;
use core_test_support::responses::start_mock_server;
use core_test_support::skip_if_host_windows;
use core_test_support::skip_if_no_network;
use core_test_support::skip_if_sandbox;
use core_test_support::skip_if_windows;
use core_test_support::skip_if_target_windows;
use core_test_support::skip_if_wine_exec;
use core_test_support::test_codex::TestCodex;
use core_test_support::test_codex::TestCodexHarness;
@@ -244,7 +245,7 @@ async fn create_workspace_directory(
async fn unified_exec_intercepts_apply_patch_exec_command() -> Result<()> {
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
skip_if_host_windows!(Ok(()));
let builder = test_codex().with_config(|config| {
config.use_experimental_unified_exec_tool = true;
@@ -386,13 +387,12 @@ async fn unified_exec_intercepts_apply_patch_exec_command() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn unified_exec_emits_exec_command_begin_event() -> Result<()> {
// TODO(anp): Remove after unified-exec fixtures use target-native commands.
skip_if_wine_exec!(
skip_if_target_windows!(
Ok(()),
"uses a POSIX command and does not assert successful execution"
);
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -450,13 +450,12 @@ async fn unified_exec_emits_exec_command_begin_event() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn unified_exec_resolves_relative_workdir() -> Result<()> {
// TODO(anp): Remove after workdir helpers use target-native paths.
skip_if_wine_exec!(
skip_if_target_windows!(
Ok(()),
"does not assert successful native-Windows workdir execution"
);
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -524,7 +523,7 @@ async fn unified_exec_resolves_relative_workdir() -> Result<()> {
async fn unified_exec_respects_workdir_override() -> Result<()> {
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
skip_if_host_windows!(Ok(()));
let server = start_mock_server().await;
@@ -588,10 +587,9 @@ async fn unified_exec_respects_workdir_override() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn unified_exec_emits_exec_command_end_event() -> Result<()> {
// TODO(anp): Remove after unified-exec fixtures use target-native commands.
skip_if_wine_exec!(Ok(()), "uses a POSIX-only command fixture");
skip_if_target_windows!(Ok(()), "uses a POSIX-only command fixture");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -663,10 +661,9 @@ async fn unified_exec_emits_exec_command_end_event() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn unified_exec_emits_output_delta_for_exec_command() -> Result<()> {
// TODO(anp): Remove after unified-exec fixtures use target-native commands.
skip_if_wine_exec!(Ok(()), "uses a POSIX-only command fixture");
skip_if_target_windows!(Ok(()), "uses a POSIX-only command fixture");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -723,10 +720,9 @@ async fn unified_exec_emits_output_delta_for_exec_command() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn unified_exec_full_lifecycle_with_background_end_event() -> Result<()> {
// TODO(anp): Remove after unified-exec fixtures use target-native commands.
skip_if_wine_exec!(Ok(()), "uses a POSIX-only command fixture");
skip_if_target_windows!(Ok(()), "uses a POSIX-only command fixture");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -820,10 +816,9 @@ async fn unified_exec_full_lifecycle_with_background_end_event() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn unified_exec_network_denial_emits_failed_background_end_event() -> Result<()> {
// TODO(anp): Remove after network-denial fixtures use target-native commands.
skip_if_wine_exec!(Ok(()), "uses the POSIX/Python network-denial fixture");
skip_if_target_windows!(Ok(()), "uses the POSIX/Python network-denial fixture");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
let (test, sandbox_policy) = unified_exec_network_denial_test(&server).await?;
@@ -865,10 +860,9 @@ async fn unified_exec_network_denial_emits_failed_background_end_event() -> Resu
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn unified_exec_short_lived_network_denial_emits_failed_end_event() -> Result<()> {
// TODO(anp): Remove after network-denial fixtures use target-native commands.
skip_if_wine_exec!(Ok(()), "uses the POSIX/Python network-denial fixture");
skip_if_target_windows!(Ok(()), "uses the POSIX/Python network-denial fixture");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
let (test, sandbox_policy) = unified_exec_network_denial_test(&server).await?;
@@ -1020,10 +1014,9 @@ async fn wait_for_unified_exec_end(
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn unified_exec_emits_terminal_interaction_for_write_stdin() -> Result<()> {
// TODO(anp): Remove after unified-exec interactive fixtures support Windows/ConPTY.
skip_if_wine_exec!(Ok(()), "uses POSIX interactive-process and EOF semantics");
skip_if_target_windows!(Ok(()), "uses POSIX interactive-process and EOF semantics");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -1105,10 +1098,9 @@ async fn unified_exec_emits_terminal_interaction_for_write_stdin() -> Result<()>
#[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_wine_exec!(Ok(()), "uses a POSIX sleep/echo timing fixture");
skip_if_target_windows!(Ok(()), "uses a POSIX sleep/echo timing fixture");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -1287,7 +1279,7 @@ async fn unified_exec_terminal_interaction_captures_delayed_output() -> Result<(
async fn unified_exec_emits_one_begin_and_one_end_event() -> Result<()> {
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
skip_if_host_windows!(Ok(()));
let server = start_mock_server().await;
@@ -1409,10 +1401,9 @@ async fn unified_exec_emits_one_begin_and_one_end_event() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn exec_command_reports_chunk_and_exit_metadata() -> Result<()> {
// TODO(anp): Remove after unified-exec fixtures use target-native commands.
skip_if_wine_exec!(Ok(()), "uses a POSIX-only command fixture");
skip_if_target_windows!(Ok(()), "uses a POSIX-only command fixture");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -1504,10 +1495,9 @@ async fn exec_command_reports_chunk_and_exit_metadata() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn exec_command_clamps_model_requested_max_output_tokens_to_policy() -> Result<()> {
// TODO(anp): Remove after unified-exec fixtures use target-native commands.
skip_if_wine_exec!(Ok(()), "uses a POSIX-only command fixture");
skip_if_target_windows!(Ok(()), "uses a POSIX-only command fixture");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -1568,10 +1558,9 @@ async fn exec_command_clamps_model_requested_max_output_tokens_to_policy() -> Re
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn write_stdin_clamps_model_requested_max_output_tokens_to_policy() -> Result<()> {
// TODO(anp): Remove after unified-exec interactive fixtures support Windows/ConPTY.
skip_if_wine_exec!(Ok(()), "uses POSIX read/while and Unix TTY semantics");
skip_if_target_windows!(Ok(()), "uses POSIX read/while and Unix TTY semantics");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -1659,10 +1648,9 @@ async fn write_stdin_clamps_model_requested_max_output_tokens_to_policy() -> Res
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn unified_exec_defaults_to_pipe() -> Result<()> {
// TODO(anp): Remove after unified-exec interactive fixtures support Windows/ConPTY.
skip_if_wine_exec!(Ok(()), "requires Python/Unix PTY support in the target");
skip_if_target_windows!(Ok(()), "requires Python/Unix PTY support in the target");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -1730,10 +1718,9 @@ async fn unified_exec_defaults_to_pipe() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn unified_exec_can_enable_tty() -> Result<()> {
// TODO(anp): Remove after unified-exec interactive fixtures support Windows/ConPTY.
skip_if_wine_exec!(Ok(()), "requires Python/Unix PTY support in the target");
skip_if_target_windows!(Ok(()), "requires Python/Unix PTY support in the target");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -1798,10 +1785,9 @@ async fn unified_exec_can_enable_tty() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn unified_exec_respects_early_exit_notifications() -> Result<()> {
// TODO(anp): Remove after unified-exec fixtures use target-native commands.
skip_if_wine_exec!(Ok(()), "uses a POSIX-only command fixture");
skip_if_target_windows!(Ok(()), "uses a POSIX-only command fixture");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -1883,10 +1869,9 @@ async fn unified_exec_respects_early_exit_notifications() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn write_stdin_returns_exit_metadata_and_clears_session() -> Result<()> {
// TODO(anp): Remove after unified-exec interactive fixtures support Windows/ConPTY.
skip_if_wine_exec!(Ok(()), "uses POSIX interactive-process and EOF semantics");
skip_if_target_windows!(Ok(()), "uses POSIX interactive-process and EOF semantics");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -2037,8 +2022,8 @@ async fn write_stdin_returns_exit_metadata_and_clears_session() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn write_stdin_ctrl_c_interrupts_non_tty_session() -> Result<()> {
// TODO(anp): Add a Wine-exec test for explicit interrupt handling on Windows.
skip_if_wine_exec!(Ok(()), "asserts Unix SIGINT and trap semantics");
// TODO(anp): Add a target-Windows test for explicit interrupt handling.
skip_if_target_windows!(Ok(()), "asserts Unix SIGINT and trap semantics");
assert_write_stdin_ctrl_c_interrupts_non_tty_session(
"trap",
"trap 'echo INT-TRAP; exit 42' INT; echo READY; while true; do sleep 30; done",
@@ -2050,8 +2035,8 @@ async fn write_stdin_ctrl_c_interrupts_non_tty_session() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn write_stdin_ctrl_c_default_interrupt_reports_130_for_non_tty_session() -> Result<()> {
// TODO(anp): Add a Wine-exec test for Windows Ctrl+C termination and exit reporting.
skip_if_wine_exec!(Ok(()), "asserts Unix SIGINT and exit-code semantics");
// TODO(anp): Add a target-Windows test for Ctrl+C termination and exit reporting.
skip_if_target_windows!(Ok(()), "asserts Unix SIGINT and exit-code semantics");
assert_write_stdin_ctrl_c_interrupts_non_tty_session(
"default",
"echo READY; exec sleep 30",
@@ -2069,7 +2054,6 @@ async fn assert_write_stdin_ctrl_c_interrupts_non_tty_session(
) -> Result<()> {
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -2286,10 +2270,9 @@ async fn write_stdin_ctrl_c_reports_unsupported_interrupt_to_model_on_windows()
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn unified_exec_emits_end_event_when_session_dies_via_stdin() -> Result<()> {
// TODO(anp): Remove after unified-exec interactive fixtures support Windows/ConPTY.
skip_if_wine_exec!(Ok(()), "uses POSIX interactive-process and EOF semantics");
skip_if_target_windows!(Ok(()), "uses POSIX interactive-process and EOF semantics");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -2381,7 +2364,7 @@ async fn unified_exec_emits_end_event_when_session_dies_via_stdin() -> Result<()
async fn unified_exec_keeps_long_running_session_after_turn_end() -> Result<()> {
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
skip_if_host_windows!(Ok(()));
let server = start_mock_server().await;
@@ -2491,7 +2474,7 @@ async fn unified_exec_keeps_long_running_session_after_turn_end() -> Result<()>
async fn unified_exec_interrupt_preserves_long_running_session() -> Result<()> {
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
skip_if_host_windows!(Ok(()));
let server = start_mock_server().await;
@@ -2588,10 +2571,9 @@ async fn unified_exec_interrupt_preserves_long_running_session() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn unified_exec_reuses_session_via_stdin() -> Result<()> {
// TODO(anp): Remove after unified-exec interactive fixtures support Windows/ConPTY.
skip_if_wine_exec!(Ok(()), "uses POSIX interactive-process and EOF semantics");
skip_if_target_windows!(Ok(()), "uses POSIX interactive-process and EOF semantics");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -2688,10 +2670,9 @@ async fn unified_exec_reuses_session_via_stdin() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn unified_exec_streams_after_lagged_output() -> Result<()> {
// TODO(anp): Remove after output fixtures use target-native commands.
skip_if_wine_exec!(Ok(()), "requires Python/Unix PTY support in the target");
skip_if_target_windows!(Ok(()), "requires Python/Unix PTY support in the target");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -2806,10 +2787,9 @@ PY
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn unified_exec_timeout_and_followup_poll() -> Result<()> {
// TODO(anp): Remove after unified-exec fixtures use target-native commands.
skip_if_wine_exec!(Ok(()), "uses a POSIX-only command fixture");
skip_if_target_windows!(Ok(()), "uses a POSIX-only command fixture");
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -2897,13 +2877,12 @@ async fn unified_exec_timeout_and_followup_poll() -> Result<()> {
#[cfg(not(target_arch = "arm"))]
async fn unified_exec_formats_large_output_summary() -> Result<()> {
// TODO(anp): Remove after output fixtures use target-native commands.
skip_if_wine_exec!(
skip_if_target_windows!(
Ok(()),
"requires Python and POSIX heredoc support in the target"
);
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
let server = start_mock_server().await;
@@ -2974,7 +2953,7 @@ PY
async fn unified_exec_runs_under_sandbox() -> Result<()> {
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
skip_if_host_windows!(Ok(()));
let server = start_mock_server().await;
@@ -3408,7 +3387,7 @@ async fn unified_exec_runs_on_all_platforms() -> Result<()> {
async fn unified_exec_prunes_exited_sessions_first() -> Result<()> {
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
skip_if_windows!(Ok(()));
skip_if_host_windows!(Ok(()));
let server = start_mock_server().await;
+9 -6
View File
@@ -30,7 +30,7 @@ use codex_protocol::protocol::TurnEnvironmentSelection;
use codex_protocol::user_input::UserInput;
use codex_utils_path_uri::PathUri;
use core_test_support::PathExt;
use core_test_support::get_remote_test_env;
use core_test_support::is_remote_test_environment;
use core_test_support::responses;
use core_test_support::responses::ev_assistant_message;
use core_test_support::responses::ev_completed;
@@ -41,10 +41,12 @@ use core_test_support::responses::mount_sse_sequence;
use core_test_support::responses::sse;
use core_test_support::responses::start_mock_server;
use core_test_support::skip_if_no_network;
use core_test_support::skip_if_no_remote_env;
use core_test_support::test_codex::TestCodex;
use core_test_support::test_codex::local;
use core_test_support::test_codex::test_codex;
use core_test_support::test_codex::turn_permission_fields;
use core_test_support::test_target_os;
use core_test_support::wait_for_event_with_timeout;
use image::DynamicImage;
use image::GenericImageView;
@@ -570,9 +572,7 @@ async fn view_image_tool_applies_local_sandbox_read_denies() -> anyhow::Result<(
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn view_image_routes_to_selected_remote_environment() -> anyhow::Result<()> {
skip_if_no_network!(Ok(()));
let Some(_remote_env) = get_remote_test_env() else {
return Ok(());
};
skip_if_no_remote_env!(Ok(()));
let server = start_mock_server().await;
let mut builder = test_codex();
@@ -1255,8 +1255,11 @@ async fn view_image_tool_turns_invalid_image_into_placeholder() -> anyhow::Resul
async fn view_image_tool_errors_when_file_missing() -> anyhow::Result<()> {
skip_if_no_network!(Ok(()));
let remote_test_env = get_remote_test_env();
println!("view_image missing-file test exec-server environment: {remote_test_env:?}");
println!(
"view_image missing-file test target: {:?}, remote: {}",
test_target_os(),
is_remote_test_environment()
);
let server = start_mock_server().await;