mirror of
https://github.com/openai/codex.git
synced 2026-05-12 15:22:39 +00:00
Compare commits
13 Commits
ww/gh-env
...
codex/fix-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1068a41fcf | ||
|
|
5976ceb8cc | ||
|
|
55b2274989 | ||
|
|
5676b840c2 | ||
|
|
63230bc9b9 | ||
|
|
b0bea0225b | ||
|
|
c7d99c63cf | ||
|
|
a04370f703 | ||
|
|
a3719d9052 | ||
|
|
7e47e850da | ||
|
|
6a3962f749 | ||
|
|
d61d3136a6 | ||
|
|
6703333d2a |
@@ -6,6 +6,7 @@ codex_rust_crate(
|
||||
integration_test_tags_extra_by_stem = {
|
||||
"all": ["flaky"],
|
||||
},
|
||||
integration_test_args = ["--test-threads=2"],
|
||||
integration_test_timeout = "long",
|
||||
test_tags = ["no-sandbox"],
|
||||
)
|
||||
|
||||
@@ -37,6 +37,7 @@ pub use responses::create_final_assistant_message_sse_response;
|
||||
pub use responses::create_request_permissions_sse_response;
|
||||
pub use responses::create_request_user_input_sse_response;
|
||||
pub use responses::create_shell_command_sse_response;
|
||||
pub use responses::create_shell_command_sse_response_from_command;
|
||||
pub use rollout::create_fake_rollout;
|
||||
pub use rollout::create_fake_rollout_with_source;
|
||||
pub use rollout::create_fake_rollout_with_text_elements;
|
||||
|
||||
@@ -10,11 +10,37 @@ pub fn create_shell_command_sse_response(
|
||||
) -> anyhow::Result<String> {
|
||||
// The `arguments` for the `shell_command` tool is a serialized JSON object.
|
||||
let command_str = shlex::try_join(command.iter().map(String::as_str))?;
|
||||
let tool_call_arguments = serde_json::to_string(&json!({
|
||||
"command": command_str,
|
||||
create_shell_command_sse_response_from_command(
|
||||
&command_str,
|
||||
workdir,
|
||||
timeout_ms,
|
||||
call_id,
|
||||
/*login*/ None,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn create_shell_command_sse_response_from_command(
|
||||
command: &str,
|
||||
workdir: Option<&Path>,
|
||||
timeout_ms: Option<u64>,
|
||||
call_id: &str,
|
||||
login: Option<bool>,
|
||||
) -> anyhow::Result<String> {
|
||||
// Use this when a test already has a shell command string. It fixes string
|
||||
// quoting for those callers by avoiding a rebuild from argv with POSIX
|
||||
// rules, which can change how Windows PowerShell parses the command; for
|
||||
// sleep-based tests, nested parsing can add another PowerShell startup
|
||||
// before the requested sleep even begins.
|
||||
let mut tool_call_arguments = json!({
|
||||
"command": command,
|
||||
"workdir": workdir.map(|w| w.to_string_lossy()),
|
||||
"timeout_ms": timeout_ms
|
||||
}))?;
|
||||
});
|
||||
if let Some(login) = login {
|
||||
tool_call_arguments["login"] = json!(login);
|
||||
}
|
||||
|
||||
let tool_call_arguments = serde_json::to_string(&tool_call_arguments)?;
|
||||
Ok(responses::sse(vec![
|
||||
responses::ev_response_created("resp-1"),
|
||||
responses::ev_function_call(call_id, "shell_command", &tool_call_arguments),
|
||||
|
||||
@@ -17,6 +17,7 @@ use codex_login::REFRESH_TOKEN_URL_OVERRIDE_ENV_VAR;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::path::Path;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::sleep;
|
||||
use tokio::time::timeout;
|
||||
use wiremock::Mock;
|
||||
use wiremock::MockServer;
|
||||
@@ -24,7 +25,24 @@ use wiremock::ResponseTemplate;
|
||||
use wiremock::matchers::method;
|
||||
use wiremock::matchers::path;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
async fn wait_for_received_requests(server: &MockServer, expected: usize) -> Result<()> {
|
||||
timeout(DEFAULT_READ_TIMEOUT, async {
|
||||
loop {
|
||||
let received = server
|
||||
.received_requests()
|
||||
.await
|
||||
.map_or(0, |requests| requests.len());
|
||||
if received >= expected {
|
||||
break;
|
||||
}
|
||||
sleep(std::time::Duration::from_millis(25)).await;
|
||||
}
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_config_toml_custom_provider(
|
||||
codex_home: &Path,
|
||||
@@ -373,6 +391,7 @@ async fn get_auth_status_omits_token_after_proactive_refresh_failure() -> Result
|
||||
)
|
||||
.await?;
|
||||
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;
|
||||
wait_for_received_requests(&server, /*expected*/ 1).await?;
|
||||
|
||||
let request_id = mcp
|
||||
.send_get_auth_status_request(GetAuthStatusParams {
|
||||
@@ -440,6 +459,7 @@ async fn get_auth_status_returns_token_after_proactive_refresh_recovery() -> Res
|
||||
)
|
||||
.await?;
|
||||
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;
|
||||
wait_for_received_requests(&server, /*expected*/ 1).await?;
|
||||
|
||||
let failed_request_id = mcp
|
||||
.send_get_auth_status_request(GetAuthStatusParams {
|
||||
|
||||
@@ -15,7 +15,7 @@ use std::path::PathBuf;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
const FILENAME_TS: &str = "2025-01-02T12-00-00";
|
||||
const META_RFC3339: &str = "2025-01-02T12:00:00Z";
|
||||
const UPDATED_AT_RFC3339: &str = "2025-01-02T12:00:00.000Z";
|
||||
|
||||
@@ -11,7 +11,7 @@ use std::path::Path;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
const SHORT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(500);
|
||||
const STOP_GRACE_PERIOD: std::time::Duration = std::time::Duration::from_millis(250);
|
||||
const SESSION_UPDATED_METHOD: &str = "fuzzyFileSearch/sessionUpdated";
|
||||
|
||||
@@ -56,7 +56,7 @@ use tokio::net::TcpListener;
|
||||
use tokio::task::JoinHandle;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn list_apps_returns_empty_when_connectors_disabled() -> Result<()> {
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::path::Path;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn turn_start_forwards_client_metadata_to_responses_request_v2() -> Result<()> {
|
||||
|
||||
@@ -21,7 +21,7 @@ use pretty_assertions::assert_eq;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
/// Confirms the server returns the default collaboration mode presets in a stable order.
|
||||
#[tokio::test]
|
||||
|
||||
@@ -38,7 +38,7 @@ use std::collections::BTreeMap;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
const AUTO_COMPACT_LIMIT: i64 = 1_000;
|
||||
const COMPACT_PROMPT: &str = "Summarize the conversation.";
|
||||
const INVALID_REQUEST_ERROR_CODE: i64 = -32600;
|
||||
|
||||
@@ -33,7 +33,7 @@ use serde_json::json;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
fn write_config(codex_home: &TempDir, contents: &str) -> Result<()> {
|
||||
Ok(std::fs::write(
|
||||
|
||||
@@ -47,7 +47,7 @@ use tokio_tungstenite::tungstenite::http::HeaderValue;
|
||||
use tokio_tungstenite::tungstenite::http::header::AUTHORIZATION;
|
||||
use tokio_tungstenite::tungstenite::http::header::ORIGIN;
|
||||
|
||||
pub(super) const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
pub(super) const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
pub(super) type WsClient = WebSocketStream<MaybeTlsStream<tokio::net::TcpStream>>;
|
||||
type HmacSha256 = Hmac<Sha256>;
|
||||
|
||||
@@ -34,7 +34,7 @@ use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
use wiremock::MockServer;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
/// Ensures dynamic tool specs are serialized into the model request payload.
|
||||
#[tokio::test]
|
||||
|
||||
@@ -24,7 +24,7 @@ use std::time::Duration;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn mock_experimental_method_requires_experimental_api_capability() -> Result<()> {
|
||||
|
||||
@@ -24,7 +24,7 @@ use std::collections::BTreeMap;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn experimental_feature_list_returns_feature_metadata_with_stage() -> Result<()> {
|
||||
|
||||
@@ -27,7 +27,7 @@ use std::os::unix::fs::symlink;
|
||||
#[cfg(unix)]
|
||||
use std::process::Command;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
async fn initialized_mcp(codex_home: &TempDir) -> Result<McpProcess> {
|
||||
let mut mcp = McpProcess::new(codex_home.path()).await?;
|
||||
|
||||
@@ -24,7 +24,7 @@ use std::time::Duration;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn initialize_uses_client_info_name_as_originator() -> Result<()> {
|
||||
|
||||
@@ -10,7 +10,7 @@ use tempfile::TempDir;
|
||||
use tokio::time::Duration;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn marketplace_add_local_directory_source() -> Result<()> {
|
||||
|
||||
@@ -34,7 +34,7 @@ use tempfile::TempDir;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
const TEST_RESOURCE_URI: &str = "test://codex/resource";
|
||||
const TEST_BLOB_RESOURCE_URI: &str = "test://codex/resource.bin";
|
||||
const TEST_RESOURCE_BLOB: &str = "YmluYXJ5LXJlc291cmNl";
|
||||
|
||||
@@ -63,7 +63,7 @@ use tokio::net::TcpListener;
|
||||
use tokio::task::JoinHandle;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
const CONNECTOR_ID: &str = "calendar";
|
||||
const CONNECTOR_NAME: &str = "Calendar";
|
||||
const TOOL_NAMESPACE: &str = "mcp__codex_apps__calendar";
|
||||
|
||||
@@ -35,7 +35,7 @@ use tokio::net::TcpListener;
|
||||
use tokio::task::JoinHandle;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn mcp_server_status_list_returns_raw_server_and_tool_names() -> Result<()> {
|
||||
|
||||
@@ -39,7 +39,7 @@ use tokio::net::TcpListener;
|
||||
use tokio::task::JoinHandle;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
const TEST_SERVER_NAME: &str = "tool_server";
|
||||
const TEST_TOOL_NAME: &str = "echo_tool";
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
use uuid::Uuid;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn memory_reset_clears_memory_files_and_rows_preserves_threads() -> Result<()> {
|
||||
|
||||
@@ -17,7 +17,7 @@ use pretty_assertions::assert_eq;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
const INVALID_REQUEST_ERROR_CODE: i64 = -32600;
|
||||
|
||||
fn model_from_preset(preset: &ModelPreset) -> Model {
|
||||
|
||||
@@ -15,7 +15,7 @@ use std::path::Path;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn turn_start_accepts_output_schema_v2() -> Result<()> {
|
||||
|
||||
@@ -33,7 +33,7 @@ use tokio::time::sleep;
|
||||
use tokio::time::timeout;
|
||||
use wiremock::MockServer;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
async fn plan_mode_uses_proposed_plan_block_for_plan_item() -> Result<()> {
|
||||
|
||||
@@ -51,7 +51,7 @@ use wiremock::matchers::header;
|
||||
use wiremock::matchers::method;
|
||||
use wiremock::matchers::path;
|
||||
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn plugin_install_rejects_relative_marketplace_paths() -> Result<()> {
|
||||
|
||||
@@ -30,7 +30,7 @@ use wiremock::matchers::method;
|
||||
use wiremock::matchers::path;
|
||||
use wiremock::matchers::query_param;
|
||||
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
const TEST_CURATED_PLUGIN_SHA: &str = "0123456789abcdef0123456789abcdef01234567";
|
||||
const STARTUP_REMOTE_PLUGIN_SYNC_MARKER_FILE: &str = ".tmp/app-server-remote-plugin-sync-v1";
|
||||
|
||||
@@ -733,10 +733,18 @@ async fn plugin_list_accepts_legacy_string_default_prompt() -> Result<()> {
|
||||
#[tokio::test]
|
||||
async fn plugin_list_force_remote_sync_returns_remote_sync_error_on_fail_open() -> Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
write_plugin_sync_config(codex_home.path(), "https://chatgpt.com/backend-api/")?;
|
||||
let server = MockServer::start().await;
|
||||
write_plugin_sync_config(codex_home.path(), &format!("{}/backend-api/", server.uri()))?;
|
||||
write_openai_curated_marketplace(codex_home.path(), &["linear"])?;
|
||||
write_installed_plugin(&codex_home, "openai-curated", "linear")?;
|
||||
|
||||
Mock::given(method("GET"))
|
||||
.and(path("/backend-api/plugins/featured"))
|
||||
.and(query_param("platform", "codex"))
|
||||
.respond_with(ResponseTemplate::new(200).set_body_string("[]"))
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let mut mcp = McpProcess::new(codex_home.path()).await?;
|
||||
timeout(DEFAULT_TIMEOUT, mcp.initialize()).await??;
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ use tokio::net::TcpListener;
|
||||
use tokio::task::JoinHandle;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn plugin_read_returns_plugin_details_with_bundle_contents() -> Result<()> {
|
||||
|
||||
@@ -23,7 +23,7 @@ use wiremock::matchers::header;
|
||||
use wiremock::matchers::method;
|
||||
use wiremock::matchers::path;
|
||||
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn plugin_uninstall_removes_plugin_cache_and_config_entry() -> Result<()> {
|
||||
|
||||
@@ -24,7 +24,7 @@ use wiremock::matchers::header;
|
||||
use wiremock::matchers::method;
|
||||
use wiremock::matchers::path;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
const INVALID_REQUEST_ERROR_CODE: i64 = -32600;
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -71,7 +71,7 @@ use wiremock::matchers::method;
|
||||
use wiremock::matchers::path;
|
||||
use wiremock::matchers::path_regex;
|
||||
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
const STARTUP_CONTEXT_HEADER: &str = "Startup context from Codex.";
|
||||
const V2_STEERING_ACKNOWLEDGEMENT: &str =
|
||||
"This was sent to steer the previous background agent task.";
|
||||
|
||||
@@ -18,7 +18,7 @@ use codex_app_server_protocol::TurnStartResponse;
|
||||
use codex_app_server_protocol::UserInput as V2UserInput;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
async fn request_permissions_round_trip() -> Result<()> {
|
||||
|
||||
@@ -20,7 +20,7 @@ use codex_protocol::config_types::Settings;
|
||||
use codex_protocol::openai_models::ReasoningEffort;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
async fn request_user_input_round_trip() -> Result<()> {
|
||||
|
||||
@@ -30,7 +30,7 @@ use serde_json::json;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
const INVALID_REQUEST_ERROR_CODE: i64 = -32600;
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -20,7 +20,7 @@ use pretty_assertions::assert_eq;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
const REQUESTED_MODEL: &str = "gpt-5.1-codex-max";
|
||||
const SERVER_MODEL: &str = "gpt-5.2-codex";
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ use pretty_assertions::assert_eq;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
const WATCHER_TIMEOUT: Duration = Duration::from_secs(20);
|
||||
|
||||
fn write_skill(root: &TempDir, name: &str) -> Result<()> {
|
||||
|
||||
@@ -25,7 +25,7 @@ use std::path::Path;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_archive_requires_materialized_rollout() -> Result<()> {
|
||||
|
||||
@@ -43,7 +43,7 @@ use super::analytics::enable_analytics_capture;
|
||||
use super::analytics::thread_initialized_event;
|
||||
use super::analytics::wait_for_analytics_payload;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_fork_creates_new_thread_and_emits_started() -> Result<()> {
|
||||
|
||||
@@ -21,7 +21,7 @@ use std::path::Path;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_inject_items_adds_raw_response_items_to_thread_history() -> Result<()> {
|
||||
|
||||
@@ -42,7 +42,7 @@ use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
use uuid::Uuid;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
async fn init_mcp(codex_home: &Path) -> Result<McpProcess> {
|
||||
let mut mcp = McpProcess::new(codex_home).await?;
|
||||
|
||||
@@ -13,7 +13,7 @@ use std::path::Path;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_loaded_list_returns_loaded_thread_ids() -> Result<()> {
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::sync::Arc;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_memory_mode_set_updates_loaded_thread_state() -> Result<()> {
|
||||
|
||||
@@ -32,7 +32,7 @@ use std::sync::Arc;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_metadata_update_patches_git_branch_and_returns_updated_thread() -> Result<()> {
|
||||
|
||||
@@ -36,7 +36,7 @@ use std::path::Path;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_read_returns_summary_without_turns() -> Result<()> {
|
||||
|
||||
@@ -76,7 +76,7 @@ use super::analytics::enable_analytics_capture;
|
||||
use super::analytics::thread_initialized_event;
|
||||
use super::analytics::wait_for_analytics_payload;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
const CODEX_5_2_INSTRUCTIONS_TEMPLATE_DEFAULT: &str = "You are Codex, a coding agent based on GPT-5. You and the user share the same workspace and collaborate to achieve the user's goals.";
|
||||
|
||||
async fn wait_for_responses_request_count(
|
||||
|
||||
@@ -20,7 +20,7 @@ use serde_json::Value;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_rollback_drops_last_turns_and_persists_to_rollout() -> Result<()> {
|
||||
|
||||
@@ -35,7 +35,7 @@ use std::path::Path;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_shell_command_runs_as_standalone_turn_and_persists_history() -> Result<()> {
|
||||
|
||||
@@ -44,7 +44,7 @@ use super::analytics::mount_analytics_capture;
|
||||
use super::analytics::thread_initialized_event;
|
||||
use super::analytics::wait_for_analytics_payload;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_start_creates_thread_and_emits_started() -> Result<()> {
|
||||
|
||||
@@ -19,7 +19,7 @@ use codex_app_server_protocol::UserInput as V2UserInput;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
async fn thread_status_changed_emits_runtime_updates() -> Result<()> {
|
||||
|
||||
@@ -4,7 +4,7 @@ use app_test_support::McpProcess;
|
||||
use app_test_support::create_final_assistant_message_sse_response;
|
||||
use app_test_support::create_mock_responses_server_repeating_assistant;
|
||||
use app_test_support::create_mock_responses_server_sequence_unchecked;
|
||||
use app_test_support::create_shell_command_sse_response;
|
||||
use app_test_support::create_shell_command_sse_response_from_command;
|
||||
use app_test_support::to_response;
|
||||
use codex_app_server_protocol::ItemStartedNotification;
|
||||
use codex_app_server_protocol::JSONRPCResponse;
|
||||
@@ -30,7 +30,7 @@ use pretty_assertions::assert_eq;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
async fn wait_for_responses_request_count_to_stabilize(
|
||||
server: &wiremock::MockServer,
|
||||
@@ -129,13 +129,9 @@ async fn thread_unsubscribe_keeps_thread_loaded_until_idle_timeout() -> Result<(
|
||||
#[tokio::test]
|
||||
async fn thread_unsubscribe_during_turn_keeps_turn_running() -> Result<()> {
|
||||
#[cfg(target_os = "windows")]
|
||||
let shell_command = vec![
|
||||
"powershell".to_string(),
|
||||
"-Command".to_string(),
|
||||
"Start-Sleep -Seconds 1".to_string(),
|
||||
];
|
||||
let shell_command = "Start-Sleep -Seconds 1";
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let shell_command = vec!["sleep".to_string(), "1".to_string()];
|
||||
let shell_command = "sleep 1";
|
||||
|
||||
let tmp = TempDir::new()?;
|
||||
let codex_home = tmp.path().join("codex_home");
|
||||
@@ -144,11 +140,12 @@ async fn thread_unsubscribe_during_turn_keeps_turn_running() -> Result<()> {
|
||||
std::fs::create_dir(&working_directory)?;
|
||||
|
||||
let server = create_mock_responses_server_sequence_unchecked(vec![
|
||||
create_shell_command_sse_response(
|
||||
shell_command.clone(),
|
||||
create_shell_command_sse_response_from_command(
|
||||
shell_command,
|
||||
Some(&working_directory),
|
||||
Some(10_000),
|
||||
"call_sleep",
|
||||
Some(false),
|
||||
)?,
|
||||
create_final_assistant_message_sse_response("Done")?,
|
||||
])
|
||||
|
||||
@@ -23,7 +23,7 @@ use codex_app_server_protocol::UserInput as V2UserInput;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn turn_interrupt_aborts_running_turn() -> Result<()> {
|
||||
|
||||
@@ -73,7 +73,7 @@ use super::analytics::wait_for_analytics_event;
|
||||
#[cfg(windows)]
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(25);
|
||||
#[cfg(not(windows))]
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
const TEST_ORIGINATOR: &str = "codex_vscode";
|
||||
const LOCAL_PRAGMATIC_TEMPLATE: &str = "You are a deeply pragmatic, effective software engineer.";
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ use tokio::time::timeout;
|
||||
#[cfg(windows)]
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(15);
|
||||
#[cfg(not(windows))]
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn turn_start_shell_zsh_fork_executes_command_v2() -> Result<()> {
|
||||
|
||||
@@ -27,7 +27,7 @@ use tokio::time::timeout;
|
||||
use super::analytics::enable_analytics_capture;
|
||||
use super::analytics::wait_for_analytics_event;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn turn_steer_requires_active_turn() -> Result<()> {
|
||||
|
||||
@@ -15,7 +15,7 @@ use std::collections::BTreeMap;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
|
||||
|
||||
#[tokio::test]
|
||||
async fn windows_sandbox_setup_start_emits_completion_notification() -> Result<()> {
|
||||
|
||||
@@ -186,7 +186,7 @@ async fn wait_for_subagent_notification(parent_thread: &Arc<CodexThread>) -> boo
|
||||
sleep(Duration::from_millis(25)).await;
|
||||
}
|
||||
};
|
||||
timeout(Duration::from_secs(2), wait).await.is_ok()
|
||||
timeout(Duration::from_secs(30), wait).await.is_ok()
|
||||
}
|
||||
|
||||
async fn persist_thread_for_tree_resume(thread: &Arc<CodexThread>, message: &str) {
|
||||
|
||||
@@ -252,6 +252,7 @@ async fn exec_full_buffer_capture_ignores_expiration() -> Result<()> {
|
||||
"powershell.exe".to_string(),
|
||||
"-NonInteractive".to_string(),
|
||||
"-NoLogo".to_string(),
|
||||
"-NoProfile".to_string(),
|
||||
"-Command".to_string(),
|
||||
"Start-Sleep -Milliseconds 50; [Console]::Out.Write('hello')".to_string(),
|
||||
];
|
||||
@@ -334,6 +335,7 @@ async fn process_exec_tool_call_preserves_full_buffer_capture_policy() -> Result
|
||||
"powershell.exe".to_string(),
|
||||
"-NonInteractive".to_string(),
|
||||
"-NoLogo".to_string(),
|
||||
"-NoProfile".to_string(),
|
||||
"-Command".to_string(),
|
||||
format!("Start-Sleep -Milliseconds 50; [Console]::Out.Write('a' * {byte_count})"),
|
||||
];
|
||||
@@ -1014,6 +1016,7 @@ fn long_running_command() -> Vec<String> {
|
||||
"powershell.exe".to_string(),
|
||||
"-NonInteractive".to_string(),
|
||||
"-NoLogo".to_string(),
|
||||
"-NoProfile".to_string(),
|
||||
"-Command".to_string(),
|
||||
"Start-Sleep -Seconds 30".to_string(),
|
||||
]
|
||||
|
||||
@@ -276,12 +276,18 @@ mod tests {
|
||||
|
||||
let config = fs::read_to_string(codex_home.path().join(codex_config::CONFIG_TOML_FILE))?;
|
||||
let config: toml::Value = toml::from_str(&config)?;
|
||||
let marketplace = config
|
||||
.get("marketplaces")
|
||||
.and_then(toml::Value::as_table)
|
||||
.and_then(|marketplaces| marketplaces.get("debug"))
|
||||
.and_then(toml::Value::as_table)
|
||||
.expect("debug marketplace should be present in config");
|
||||
assert_eq!(
|
||||
config["marketplaces"]["debug"]["source_type"].as_str(),
|
||||
marketplace.get("source_type").and_then(toml::Value::as_str),
|
||||
Some("local")
|
||||
);
|
||||
assert_eq!(
|
||||
config["marketplaces"]["debug"]["source"].as_str(),
|
||||
marketplace.get("source").and_then(toml::Value::as_str),
|
||||
Some(expected_source.as_str())
|
||||
);
|
||||
Ok(())
|
||||
|
||||
@@ -130,6 +130,16 @@ fn looks_like_local_path(source: &str) -> bool {
|
||||
|| source.starts_with("~/")
|
||||
|| source == "."
|
||||
|| source == ".."
|
||||
|| {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
source.starts_with(".\\") || source.starts_with("..\\") || source.starts_with('\\')
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_local_source_path(source: &str) -> Result<PathBuf, MarketplaceAddError> {
|
||||
@@ -310,6 +320,14 @@ mod tests {
|
||||
assert!(path.is_absolute());
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
fn windows_backslash_relative_path_looks_local() {
|
||||
assert!(looks_like_local_path(r".\marketplace"));
|
||||
assert!(looks_like_local_path(r"..\marketplace"));
|
||||
assert!(looks_like_local_path(r"\marketplace"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn local_file_source_is_rejected() {
|
||||
let tempdir = TempDir::new().unwrap();
|
||||
|
||||
@@ -55,6 +55,7 @@ use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::sync::Notify;
|
||||
use tokio::time::timeout;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
@@ -153,33 +154,35 @@ async fn wait_for_turn_aborted(
|
||||
expected_turn_id: &str,
|
||||
expected_reason: TurnAbortReason,
|
||||
) {
|
||||
timeout(Duration::from_secs(5), async {
|
||||
loop {
|
||||
let event = thread
|
||||
.next_event()
|
||||
.await
|
||||
.expect("child thread should emit events");
|
||||
if matches!(
|
||||
event.msg,
|
||||
EventMsg::TurnAborted(TurnAbortedEvent {
|
||||
turn_id: Some(ref turn_id),
|
||||
ref reason,
|
||||
..
|
||||
}) if turn_id == expected_turn_id && *reason == expected_reason
|
||||
) {
|
||||
let deadline = tokio::time::Instant::now() + Duration::from_secs(15);
|
||||
let mut seen_aborts = Vec::new();
|
||||
loop {
|
||||
let remaining = deadline.saturating_duration_since(tokio::time::Instant::now());
|
||||
let event = timeout(remaining, thread.next_event())
|
||||
.await
|
||||
.unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"expected child turn {expected_turn_id} to be aborted with {expected_reason:?}; saw aborts: {seen_aborts:?}"
|
||||
)
|
||||
})
|
||||
.expect("child thread should emit events");
|
||||
if let EventMsg::TurnAborted(TurnAbortedEvent {
|
||||
turn_id, reason, ..
|
||||
}) = event.msg
|
||||
{
|
||||
if turn_id.as_deref() == Some(expected_turn_id) && reason == expected_reason {
|
||||
break;
|
||||
}
|
||||
seen_aborts.push((turn_id, reason));
|
||||
}
|
||||
})
|
||||
.await
|
||||
.expect("expected child turn to be interrupted");
|
||||
}
|
||||
}
|
||||
|
||||
async fn wait_for_redirected_envelope_in_history(
|
||||
thread: &Arc<CodexThread>,
|
||||
expected: &InterAgentCommunication,
|
||||
) {
|
||||
timeout(Duration::from_secs(5), async {
|
||||
timeout(Duration::from_secs(30), async {
|
||||
loop {
|
||||
let history_items = thread
|
||||
.codex
|
||||
@@ -216,8 +219,9 @@ async fn wait_for_redirected_envelope_in_history(
|
||||
.expect("redirected followup envelope should appear in history");
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct NeverEndingTask;
|
||||
struct NeverEndingTask {
|
||||
started: Arc<Notify>,
|
||||
}
|
||||
|
||||
impl SessionTask for NeverEndingTask {
|
||||
fn kind(&self) -> TaskKind {
|
||||
@@ -235,6 +239,7 @@ impl SessionTask for NeverEndingTask {
|
||||
_input: Vec<UserInput>,
|
||||
cancellation_token: CancellationToken,
|
||||
) -> Option<String> {
|
||||
self.started.notify_one();
|
||||
cancellation_token.cancelled().await;
|
||||
None
|
||||
}
|
||||
@@ -1518,6 +1523,7 @@ async fn multi_agent_v2_followup_task_interrupts_busy_child_without_losing_messa
|
||||
|
||||
let active_turn = thread.codex.session.new_default_turn().await;
|
||||
let interrupted_turn_id = active_turn.sub_id.clone();
|
||||
let never_ending_task_started = Arc::new(Notify::new());
|
||||
thread
|
||||
.codex
|
||||
.session
|
||||
@@ -1527,9 +1533,17 @@ async fn multi_agent_v2_followup_task_interrupts_busy_child_without_losing_messa
|
||||
text: "working".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
NeverEndingTask,
|
||||
NeverEndingTask {
|
||||
started: Arc::clone(&never_ending_task_started),
|
||||
},
|
||||
)
|
||||
.await;
|
||||
timeout(
|
||||
Duration::from_secs(15),
|
||||
never_ending_task_started.notified(),
|
||||
)
|
||||
.await
|
||||
.expect("child task should start before the interrupting followup");
|
||||
|
||||
FollowupTaskHandlerV2
|
||||
.handle(invocation(
|
||||
|
||||
@@ -14,6 +14,7 @@ pub fn create_shell_command_sse_response(
|
||||
"command": command_str,
|
||||
"workdir": workdir.map(|w| w.to_string_lossy()),
|
||||
"timeout_ms": timeout_ms,
|
||||
"login": false,
|
||||
}))?;
|
||||
let response_id = format!("resp-{call_id}");
|
||||
Ok(responses::sse(vec![
|
||||
|
||||
@@ -27,7 +27,7 @@ use mcp_test_support::create_apply_patch_sse_response;
|
||||
use mcp_test_support::create_final_assistant_message_sse_response;
|
||||
use mcp_test_support::create_mock_responses_server;
|
||||
use mcp_test_support::create_shell_command_sse_response;
|
||||
use mcp_test_support::format_with_current_shell;
|
||||
use mcp_test_support::format_with_current_shell_non_login;
|
||||
|
||||
// Allow ample time on slower CI or under load to avoid flakes.
|
||||
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(20);
|
||||
@@ -70,8 +70,8 @@ async fn shell_command_approval_triggers_elicitation() -> anyhow::Result<()> {
|
||||
created_filename.to_string(),
|
||||
"-Force".to_string(),
|
||||
],
|
||||
// `powershell.exe` startup can be slow on loaded Windows CI workers
|
||||
10_000,
|
||||
// `powershell.exe` startup can be slow on loaded Windows CI workers.
|
||||
30_000,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
@@ -79,8 +79,9 @@ async fn shell_command_approval_triggers_elicitation() -> anyhow::Result<()> {
|
||||
5_000,
|
||||
)
|
||||
};
|
||||
let expected_shell_command =
|
||||
format_with_current_shell(&shlex::try_join(shell_command.iter().map(String::as_str))?);
|
||||
let expected_shell_command = format_with_current_shell_non_login(&shlex::try_join(
|
||||
shell_command.iter().map(String::as_str),
|
||||
)?);
|
||||
|
||||
let McpHandle {
|
||||
process: mut mcp_process,
|
||||
|
||||
@@ -8153,6 +8153,17 @@ mod tests {
|
||||
let (mut app, _app_event_rx, _op_rx) = make_test_app_with_channels().await;
|
||||
let codex_home = tempdir()?;
|
||||
app.config.codex_home = codex_home.path().to_path_buf().abs();
|
||||
app.config.sqlite_home = codex_home.path().to_path_buf();
|
||||
let state_db = codex_state::StateRuntime::init(
|
||||
codex_home.path().to_path_buf(),
|
||||
app.config.model_provider_id.clone(),
|
||||
)
|
||||
.await
|
||||
.expect("state db should initialize");
|
||||
state_db
|
||||
.mark_backfill_complete(/*last_watermark*/ None)
|
||||
.await
|
||||
.expect("state db backfill should be marked complete");
|
||||
|
||||
let mut app_server = crate::start_embedded_app_server_for_picker(&app.config).await?;
|
||||
let started = app_server.start_thread(&app.config).await?;
|
||||
@@ -8166,16 +8177,20 @@ mod tests {
|
||||
)
|
||||
.await;
|
||||
|
||||
let state_db = codex_state::StateRuntime::init(
|
||||
codex_home.path().to_path_buf(),
|
||||
app.config.model_provider_id.clone(),
|
||||
)
|
||||
let memory_mode = time::timeout(Duration::from_secs(10), async {
|
||||
loop {
|
||||
let memory_mode = state_db
|
||||
.get_thread_memory_mode(thread_id)
|
||||
.await
|
||||
.expect("thread memory mode should be readable");
|
||||
if memory_mode.as_deref() == Some("disabled") {
|
||||
break memory_mode;
|
||||
}
|
||||
time::sleep(Duration::from_millis(50)).await;
|
||||
}
|
||||
})
|
||||
.await
|
||||
.expect("state db should initialize");
|
||||
let memory_mode = state_db
|
||||
.get_thread_memory_mode(thread_id)
|
||||
.await
|
||||
.expect("thread memory mode should be readable");
|
||||
.expect("thread memory mode should update");
|
||||
assert_eq!(memory_mode.as_deref(), Some("disabled"));
|
||||
|
||||
app_server.shutdown().await?;
|
||||
|
||||
Reference in New Issue
Block a user