Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@ If you don’t have the tool:
- Prefer deep equals comparisons whenever possible. Perform `assert_eq!()` on entire objects, rather than individual fields.
- Avoid mutating process environment in tests; prefer passing environment-derived flags or dependencies from above.

### Spawning workspace binaries in tests (Cargo vs Buck2)
### Spawning workspace binaries in tests (Cargo vs Bazel)

- Prefer `codex_utils_cargo_bin::cargo_bin("...")` over `assert_cmd::Command::cargo_bin(...)` or `escargot` when tests need to spawn first-party binaries.
- Under Buck2, `CARGO_BIN_EXE_*` may be project-relative (e.g. `buck-out/...`), which breaks if a test changes its working directory. `codex_utils_cargo_bin::cargo_bin` resolves to an absolute path first.
- When locating fixture files under Buck2, avoid `env!("CARGO_MANIFEST_DIR")` (Buck codegen sets it to `"."`). Prefer deriving paths from `codex_utils_cargo_bin::buck_project_root()` when needed.
- Under Bazel, binaries and resources may live under runfiles; use `codex_utils_cargo_bin::cargo_bin` to resolve absolute paths that remain stable after `chdir`.
- When locating fixture files or test resources under Bazel, avoid `env!("CARGO_MANIFEST_DIR")`. Prefer `codex_utils_cargo_bin::find_resource!` so paths resolve correctly under both Cargo and Bazel runfiles.

### Integration tests (core)

Expand Down
2 changes: 2 additions & 0 deletions codex-rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion codex-rs/apply-patch/tests/suite/scenarios.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use codex_utils_cargo_bin::find_resource;
use pretty_assertions::assert_eq;
use std::collections::BTreeMap;
use std::fs;
Expand All @@ -8,7 +9,7 @@ use tempfile::tempdir;

#[test]
fn test_apply_patch_scenarios() -> anyhow::Result<()> {
let scenarios_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/scenarios");
let scenarios_dir = find_resource!("tests/fixtures/scenarios")?;
for scenario in fs::read_dir(scenarios_dir)? {
let scenario = scenario?;
let path = scenario.path();
Expand Down
1 change: 1 addition & 0 deletions codex-rs/chatgpt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ anyhow = { workspace = true }
clap = { workspace = true, features = ["derive"] }
codex-common = { workspace = true, features = ["cli"] }
codex-core = { workspace = true }
codex-utils-cargo-bin = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
tokio = { workspace = true, features = ["full"] }
Expand Down
4 changes: 2 additions & 2 deletions codex-rs/chatgpt/tests/suite/apply_command_e2e.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use codex_chatgpt::apply_command::apply_diff_from_task;
use codex_chatgpt::get_task::GetTaskResponse;
use std::path::Path;
use codex_utils_cargo_bin::find_resource;
use tempfile::TempDir;
use tokio::process::Command;

Expand Down Expand Up @@ -68,7 +68,7 @@ async fn create_temp_git_repo() -> anyhow::Result<TempDir> {
}

async fn mock_get_task_with_fixture() -> anyhow::Result<GetTaskResponse> {
let fixture_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/task_turn_fixture.json");
let fixture_path = find_resource!("tests/task_turn_fixture.json")?;
let fixture_content = tokio::fs::read_to_string(fixture_path).await?;
let response: GetTaskResponse = serde_json::from_str(&fixture_content)?;
Ok(response)
Expand Down
31 changes: 22 additions & 9 deletions codex-rs/core/tests/suite/cli_stream.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use assert_cmd::Command as AssertCommand;
use codex_core::RolloutRecorder;
use codex_core::protocol::GitInfo;
use codex_utils_cargo_bin::find_resource;
use core_test_support::fs_wait;
use core_test_support::skip_if_no_network;
use std::time::Duration;
Expand All @@ -12,6 +13,16 @@ use wiremock::ResponseTemplate;
use wiremock::matchers::method;
use wiremock::matchers::path;

fn repo_root() -> std::path::PathBuf {
#[expect(clippy::expect_used)]
find_resource!(".").expect("failed to resolve repo root")
}

fn cli_responses_fixture() -> std::path::PathBuf {
#[expect(clippy::expect_used)]
find_resource!("tests/cli_responses_fixture.sse").expect("failed to resolve fixture path")
}

/// Tests streaming chat completions through the CLI using a mock server.
/// This test:
/// 1. Sets up a mock server that simulates OpenAI's chat completions API
Expand All @@ -23,6 +34,7 @@ async fn chat_mode_stream_cli() {
skip_if_no_network!();

let server = MockServer::start().await;
let repo_root = repo_root();
let sse = concat!(
"data: {\"choices\":[{\"delta\":{\"content\":\"hi\"}}]}\n\n",
"data: {\"choices\":[{\"delta\":{}}]}\n\n",
Expand Down Expand Up @@ -53,7 +65,7 @@ async fn chat_mode_stream_cli() {
.arg("-c")
.arg("model_provider=\"mock\"")
.arg("-C")
.arg(env!("CARGO_MANIFEST_DIR"))
.arg(&repo_root)
.arg("hello?");
cmd.env("CODEX_HOME", home.path())
.env("OPENAI_API_KEY", "dummy")
Expand Down Expand Up @@ -127,6 +139,7 @@ async fn exec_cli_applies_experimental_instructions_file() {
);

let home = TempDir::new().unwrap();
let repo_root = repo_root();
let bin = codex_utils_cargo_bin::cargo_bin("codex").unwrap();
let mut cmd = AssertCommand::new(bin);
cmd.arg("exec")
Expand All @@ -140,7 +153,7 @@ async fn exec_cli_applies_experimental_instructions_file() {
"experimental_instructions_file=\"{custom_path_str}\""
))
.arg("-C")
.arg(env!("CARGO_MANIFEST_DIR"))
.arg(&repo_root)
.arg("hello?\n");
cmd.env("CODEX_HOME", home.path())
.env("OPENAI_API_KEY", "dummy")
Expand Down Expand Up @@ -177,16 +190,16 @@ async fn exec_cli_applies_experimental_instructions_file() {
async fn responses_api_stream_cli() {
skip_if_no_network!();

let fixture =
std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/cli_responses_fixture.sse");
let fixture = cli_responses_fixture();
let repo_root = repo_root();

let home = TempDir::new().unwrap();
let bin = codex_utils_cargo_bin::cargo_bin("codex").unwrap();
let mut cmd = AssertCommand::new(bin);
cmd.arg("exec")
.arg("--skip-git-repo-check")
.arg("-C")
.arg(env!("CARGO_MANIFEST_DIR"))
.arg(&repo_root)
.arg("hello?");
cmd.env("CODEX_HOME", home.path())
.env("OPENAI_API_KEY", "dummy")
Expand All @@ -213,16 +226,16 @@ async fn integration_creates_and_checks_session_file() -> anyhow::Result<()> {
let prompt = format!("echo {marker}");

// 3. Use the same offline SSE fixture as responses_api_stream_cli so the test is hermetic.
let fixture =
std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/cli_responses_fixture.sse");
let fixture = cli_responses_fixture();
let repo_root = repo_root();

// 4. Run the codex CLI and invoke `exec`, which is what records a session.
let bin = codex_utils_cargo_bin::cargo_bin("codex").unwrap();
let mut cmd = AssertCommand::new(bin);
cmd.arg("exec")
.arg("--skip-git-repo-check")
.arg("-C")
.arg(env!("CARGO_MANIFEST_DIR"))
.arg(&repo_root)
.arg(&prompt);
cmd.env("CODEX_HOME", home.path())
.env("OPENAI_API_KEY", "dummy")
Expand Down Expand Up @@ -343,7 +356,7 @@ async fn integration_creates_and_checks_session_file() -> anyhow::Result<()> {
cmd2.arg("exec")
.arg("--skip-git-repo-check")
.arg("-C")
.arg(env!("CARGO_MANIFEST_DIR"))
.arg(&repo_root)
.arg(&prompt2)
.arg("resume")
.arg("--last");
Expand Down
1 change: 1 addition & 0 deletions codex-rs/exec-server/tests/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ path = "lib.rs"
anyhow = { workspace = true }
codex-core = { workspace = true }
codex-utils-cargo-bin = { workspace = true }
path-absolutize = { workspace = true }
rmcp = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }
21 changes: 11 additions & 10 deletions codex-rs/exec-server/tests/common/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use codex_core::MCP_SANDBOX_STATE_METHOD;
use codex_core::SandboxState;
use codex_core::protocol::SandboxPolicy;
use codex_utils_cargo_bin::find_resource;
use path_absolutize::Absolutize;
use rmcp::ClientHandler;
use rmcp::ErrorData as McpError;
use rmcp::RoleClient;
Expand Down Expand Up @@ -35,16 +37,15 @@ where
let mcp_executable = codex_utils_cargo_bin::cargo_bin("codex-exec-mcp-server")?;
let execve_wrapper = codex_utils_cargo_bin::cargo_bin("codex-execve-wrapper")?;

// `bash` requires a special lookup when running under Bazel because it is a
// _resource_ rather than a binary target.
let bash = if let Some(bazel_runfiles_dir) = std::env::var_os("RUNFILES_DIR") {
PathBuf::from(bazel_runfiles_dir).join("_main/codex-rs/exec-server/tests/suite/bash")
} else {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("..")
.join("suite")
.join("bash")
};
// `bash` is a test resource rather than a binary target, so we must use
// `find_resource!` to locate it instead of `cargo_bin`.
//
// Note we also have to normalize (but not canonicalize!) the path for
// _Bazel_ because the original value ends with
// `codex-rs/exec-server/tests/common/../suite/bash`, but the `tests/common`
// folder will not exist at runtime under Bazel. As such, we have to
// normalize it before passing it to `dotslash fetch`.
let bash = find_resource!("../suite/bash")?.absolutize()?.to_path_buf();

// Need to ensure the artifact associated with the bash DotSlash file is
// available before it is run in a read-only sandbox.
Expand Down
4 changes: 3 additions & 1 deletion codex-rs/exec/tests/suite/auth_env.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![allow(clippy::unwrap_used, clippy::expect_used)]
use codex_utils_cargo_bin::find_resource;
use core_test_support::responses::ev_completed;
use core_test_support::responses::mount_sse_once_match;
use core_test_support::responses::sse;
Expand All @@ -10,6 +11,7 @@ use wiremock::matchers::header;
async fn exec_uses_codex_api_key_env_var() -> anyhow::Result<()> {
let test = test_codex_exec();
let server = start_mock_server().await;
let repo_root = find_resource!(".")?;

mount_sse_once_match(
&server,
Expand All @@ -21,7 +23,7 @@ async fn exec_uses_codex_api_key_env_var() -> anyhow::Result<()> {
test.cmd_with_server(&server)
.arg("--skip-git-repo-check")
.arg("-C")
.arg(env!("CARGO_MANIFEST_DIR"))
.arg(&repo_root)
.arg("echo testing codex api key")
.assert()
.success();
Expand Down
Loading
Loading