Files
codex/codex-rs/code-mode-host/src/transport_tests.rs
T
Channing Conger 60c722e075 Add a dual-WebSocket transport for code mode (#36812)
## Why

Large nested-tool callbacks can occupy a WebSocket and delay unrelated session
operations on the same code-mode connection.

## What changed

- Negotiate the optional `dual-websocket-v1` capability and pair a second,
  token-scoped WebSocket with the control connection.
- Route nested-tool callbacks and their results over the bulk socket while
  keeping session operations, notifications, and execution responses on the
  control socket. Reject messages sent on the wrong lane.
- Preserve the single-connection transport when the capability is unavailable,
  and bound pairing, queued callbacks, and deferred cross-socket messages.
- Defer callbacks that arrive before their execution-started response, and
  return delegate errors without disconnecting the connection.

## Testing

Add protocol, transport, driver, and WebSocket integration coverage for
capability negotiation, lane routing, pairing failures, out-of-order messages,
and progress during large concurrent tool results.

GitOrigin-RevId: fa4504653e7cbf3c4ec930ae57aa0a41345bad66
2026-08-03 23:48:28 +00:00

79 lines
2.3 KiB
Rust

use std::net::SocketAddr;
use pretty_assertions::assert_eq;
use super::BulkConnectionRegistry;
use super::ListenTransport;
use super::MAX_PENDING_BULK_CONNECTIONS;
use super::parse_listen_url;
#[test]
fn bulk_connection_registration_cleans_up_when_dropped() {
let registry = BulkConnectionRegistry::default();
let registration = registry.reserve().expect("bulk connection registration");
let token = registration.token();
drop(registration);
assert!(registry.remove(token).is_none());
}
#[test]
fn bulk_connection_registrations_are_bounded_and_released() {
let registry = BulkConnectionRegistry::default();
let mut registrations = (0..MAX_PENDING_BULK_CONNECTIONS)
.map(|_| registry.reserve().expect("bulk connection registration"))
.collect::<Vec<_>>();
assert!(registry.reserve().is_none());
drop(registrations.pop());
assert!(registry.reserve().is_some());
}
#[test]
fn parse_listen_url_accepts_stdio_transports() {
assert_eq!(
parse_listen_url("stdio").expect("stdio listen URL should parse"),
ListenTransport::Stdio
);
assert_eq!(
parse_listen_url("stdio://").expect("stdio URL should parse"),
ListenTransport::Stdio
);
}
#[test]
fn parse_listen_url_accepts_websocket_addresses() {
assert_eq!(
parse_listen_url("ws://127.0.0.1:0").expect("websocket listen URL should parse"),
ListenTransport::WebSocket(
"127.0.0.1:0"
.parse::<SocketAddr>()
.expect("valid socket address")
)
);
assert_eq!(
parse_listen_url("ws://[::1]:9000").expect("IPv6 websocket listen URL should parse"),
ListenTransport::WebSocket(
"[::1]:9000"
.parse::<SocketAddr>()
.expect("valid IPv6 socket address")
)
);
}
#[test]
fn parse_listen_url_rejects_invalid_transports() {
let invalid_address = parse_listen_url("ws://localhost:9000")
.expect_err("websocket listener requires an IP address");
assert!(
invalid_address
.to_string()
.contains("expected `ws://IP:PORT`")
);
let unsupported =
parse_listen_url("http://127.0.0.1:9000").expect_err("HTTP is not a listen transport");
assert!(unsupported.to_string().contains("unsupported --listen URL"));
}