use std::path::Path; use anyhow::Result; use app_test_support::app_server_json_shutdown_event; use predicates::str::contains; use pretty_assertions::assert_eq; use serde_json::json; use tempfile::TempDir; fn codex_command(codex_home: &Path) -> Result { let mut cmd = assert_cmd::Command::new(codex_utils_cargo_bin::cargo_bin("codex")?); cmd.env("CODEX_HOME", codex_home); Ok(cmd) } #[test] fn strict_config_rejects_unknown_config_fields_for_app_server() -> Result<()> { let codex_home = TempDir::new()?; std::fs::write( codex_home.path().join("config.toml"), r#" foo = "bar" "#, )?; let mut cmd = codex_command(codex_home.path())?; cmd.args(["app-server", "--strict-config", "--listen", "off"]) .assert() .failure() .stderr(contains("unknown configuration field")); Ok(()) } #[test] fn agents_accept_interactive_configuration_overrides() -> Result<()> { let codex_home = TempDir::new()?; for args in [ ["-c", "features.multi_agent_mode=true", "agents"].as_slice(), ["--enable", "multi_agent_mode", "agents"].as_slice(), ["--yolo", "agents"].as_slice(), ["--search", "agents"].as_slice(), ["--model", "gpt-5", "agents"].as_slice(), ["--approve-for-me", "agents"].as_slice(), ["--cd", ".", "agents"].as_slice(), ] { let mut cmd = codex_command(codex_home.path())?; cmd.env("TERM", "xterm-256color").args(args); #[cfg(not(unix))] cmd.args(["--remote", "ws://127.0.0.1:4512"]); cmd.assert() .failure() .stderr(contains("stdin is not a terminal")); } Ok(()) } #[test] fn agents_reject_inputs_that_cannot_be_applied() -> Result<()> { let codex_home = TempDir::new()?; for (args, expected_error) in [ ( ["--image=image.png", "agents"].as_slice(), "does not accept an initial prompt or images", ), ( ["--oss", "agents", "--remote", "ws://127.0.0.1:4512"].as_slice(), "cannot apply local provider or additional-directory overrides", ), ( [ "--add-dir", ".", "agents", "--remote", "ws://127.0.0.1:4512", ] .as_slice(), "cannot apply local provider or additional-directory overrides", ), ( [ "-c", "sandbox_workspace_write.writable_roots=[\"../shared\"]", "agents", "--remote", "ws://127.0.0.1:4512", ] .as_slice(), "cannot apply local provider or additional-directory overrides", ), ] { let mut cmd = codex_command(codex_home.path())?; cmd.args(args) .assert() .failure() .stderr(contains(expected_error)); } Ok(()) } #[test] fn app_server_emits_json_info_events() -> Result<()> { let codex_home = TempDir::new()?; let event = app_server_json_shutdown_event("codex", &["app-server"], codex_home.path())?; assert_eq!( event, json!({ "level": "INFO", "fields": { "message": "processor task exited", "exit_reason": "stdio_connection_closed", "remaining_connection_count": 0, "shutdown_forced": false, }, "target": "codex_app_server", }) ); Ok(()) }