From 5894e019b60f05b34f23251f01dd5ada259dd0ff Mon Sep 17 00:00:00 2001 From: Ruslan Nigmatullin Date: Thu, 9 Apr 2026 23:07:24 -0700 Subject: [PATCH] app-server: add pipelined config rpc regression test Motivation: Concurrent request dispatch can reorder state-dependent RPCs. Config reads and writes are lightweight enough to serialize on a global config key, so the test suite should cover pipelined write/read behavior before adding the queue implementation. Summary: Add a config/value/write followed immediately by config/read integration test that asserts the read observes the written model value. Testing: - cargo test -p codex-app-server --test all config_read_after_pipelined_write_sees_written_value - cargo test -p codex-app-server --- .../app-server/tests/suite/v2/config_rpc.rs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/codex-rs/app-server/tests/suite/v2/config_rpc.rs b/codex-rs/app-server/tests/suite/v2/config_rpc.rs index 99e33eb6b9..5c04cc3c44 100644 --- a/codex-rs/app-server/tests/suite/v2/config_rpc.rs +++ b/codex-rs/app-server/tests/suite/v2/config_rpc.rs @@ -569,6 +569,55 @@ model = "gpt-old" Ok(()) } +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn config_read_after_pipelined_write_sees_written_value() -> Result<()> { + let temp_dir = TempDir::new()?; + let codex_home = temp_dir.path().canonicalize()?; + write_config( + &temp_dir, + r#" +model = "gpt-old" +"#, + )?; + + let mut mcp = McpProcess::new(&codex_home).await?; + timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??; + + let write_id = mcp + .send_config_value_write_request(ConfigValueWriteParams { + file_path: None, + key_path: "model".to_string(), + value: json!("gpt-new"), + merge_strategy: MergeStrategy::Replace, + expected_version: None, + }) + .await?; + let read_id = mcp + .send_config_read_request(ConfigReadParams { + include_layers: false, + cwd: None, + }) + .await?; + + let write_resp: JSONRPCResponse = timeout( + DEFAULT_READ_TIMEOUT, + mcp.read_stream_until_response_message(RequestId::Integer(write_id)), + ) + .await??; + let write: ConfigWriteResponse = to_response(write_resp)?; + assert_eq!(write.status, WriteStatus::Ok); + + let read_resp: JSONRPCResponse = timeout( + DEFAULT_READ_TIMEOUT, + mcp.read_stream_until_response_message(RequestId::Integer(read_id)), + ) + .await??; + let read: ConfigReadResponse = to_response(read_resp)?; + assert_eq!(read.config.model.as_deref(), Some("gpt-new")); + + Ok(()) +} + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn config_value_write_rejects_version_conflict() -> Result<()> { let codex_home = TempDir::new()?;