mirror of
https://github.com/openai/codex.git
synced 2026-04-26 23:55:25 +00:00
Fall back to http when websockets fail (#10139)
I expect not all proxies work with websockets, fall back to http if websockets fail.
This commit is contained in:
98
codex-rs/core/tests/suite/websocket_fallback.rs
Normal file
98
codex-rs/core/tests/suite/websocket_fallback.rs
Normal file
@@ -0,0 +1,98 @@
|
||||
use anyhow::Result;
|
||||
use codex_core::WireApi;
|
||||
use core_test_support::responses;
|
||||
use core_test_support::responses::ev_completed;
|
||||
use core_test_support::responses::ev_response_created;
|
||||
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::skip_if_no_network;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use pretty_assertions::assert_eq;
|
||||
use wiremock::http::Method;
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn websocket_fallback_switches_to_http_after_retries_exhausted() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = responses::start_mock_server().await;
|
||||
let response_mock = mount_sse_once(
|
||||
&server,
|
||||
sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]),
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut builder = test_codex().with_config({
|
||||
let base_url = format!("{}/v1", server.uri());
|
||||
move |config| {
|
||||
config.model_provider.base_url = Some(base_url);
|
||||
config.model_provider.wire_api = WireApi::ResponsesWebsocket;
|
||||
config.model_provider.stream_max_retries = Some(0);
|
||||
config.model_provider.request_max_retries = Some(0);
|
||||
}
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
test.submit_turn("hello").await?;
|
||||
|
||||
let requests = server.received_requests().await.unwrap_or_default();
|
||||
let websocket_attempts = requests
|
||||
.iter()
|
||||
.filter(|req| req.method == Method::GET && req.url.path().ends_with("/responses"))
|
||||
.count();
|
||||
let http_attempts = requests
|
||||
.iter()
|
||||
.filter(|req| req.method == Method::POST && req.url.path().ends_with("/responses"))
|
||||
.count();
|
||||
|
||||
assert_eq!(websocket_attempts, 1);
|
||||
assert_eq!(http_attempts, 1);
|
||||
assert_eq!(response_mock.requests().len(), 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn websocket_fallback_is_sticky_across_turns() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = responses::start_mock_server().await;
|
||||
let response_mock = mount_sse_sequence(
|
||||
&server,
|
||||
vec![
|
||||
sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]),
|
||||
sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]),
|
||||
],
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut builder = test_codex().with_config({
|
||||
let base_url = format!("{}/v1", server.uri());
|
||||
move |config| {
|
||||
config.model_provider.base_url = Some(base_url);
|
||||
config.model_provider.wire_api = WireApi::ResponsesWebsocket;
|
||||
config.model_provider.stream_max_retries = Some(0);
|
||||
config.model_provider.request_max_retries = Some(0);
|
||||
}
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
test.submit_turn("first").await?;
|
||||
test.submit_turn("second").await?;
|
||||
|
||||
let requests = server.received_requests().await.unwrap_or_default();
|
||||
let websocket_attempts = requests
|
||||
.iter()
|
||||
.filter(|req| req.method == Method::GET && req.url.path().ends_with("/responses"))
|
||||
.count();
|
||||
let http_attempts = requests
|
||||
.iter()
|
||||
.filter(|req| req.method == Method::POST && req.url.path().ends_with("/responses"))
|
||||
.count();
|
||||
|
||||
assert_eq!(websocket_attempts, 1);
|
||||
assert_eq!(http_attempts, 2);
|
||||
assert_eq!(response_mock.requests().len(), 2);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user