Files
codex/codex-rs/uds/src/lib_tests.rs
Ruslan Nigmatullin 97d4b42583 uds: add async Unix socket crate (#18254)
## Summary
- add a codex-uds crate with async UnixListener and UnixStream wrappers
- expose helpers for private socket directory setup and stale socket
path checks
- migrate codex-stdio-to-uds onto codex-uds and Tokio-based stdio/socket
relaying
- update the CLI stdio-to-uds command path for the async runner

## Tests
- cargo test -p codex-uds -p codex-stdio-to-uds
- cargo test -p codex-cli
- just fmt
- just fix -p codex-uds
- just fix -p codex-stdio-to-uds
- just fix -p codex-cli
- just bazel-lock-check
- git diff --check
2026-04-20 15:59:05 -07:00

122 lines
3.9 KiB
Rust

use std::io::ErrorKind;
use pretty_assertions::assert_eq;
use tokio::io::AsyncReadExt;
use tokio::io::AsyncWriteExt;
use super::*;
#[tokio::test]
async fn prepare_private_socket_directory_creates_directory() {
let temp_dir = tempfile::TempDir::new().expect("temp dir");
let socket_dir = temp_dir.path().join("app-server-control");
prepare_private_socket_directory(&socket_dir)
.await
.expect("socket dir should be created");
assert!(socket_dir.is_dir());
}
#[cfg(unix)]
#[tokio::test]
async fn prepare_private_socket_directory_sets_existing_permissions_to_owner_only() {
use std::os::unix::fs::PermissionsExt;
let temp_dir = tempfile::TempDir::new().expect("temp dir");
for mode in [0o755, 0o600] {
let socket_dir = temp_dir.path().join(format!("app-server-control-{mode:o}"));
std::fs::create_dir(&socket_dir).expect("socket dir should be created");
std::fs::set_permissions(&socket_dir, std::fs::Permissions::from_mode(mode))
.expect("socket dir permissions should be changed");
prepare_private_socket_directory(&socket_dir)
.await
.expect("socket dir permissions should be set exactly");
let mode = std::fs::metadata(&socket_dir)
.expect("socket dir metadata")
.permissions()
.mode();
assert_eq!(mode & 0o777, 0o700);
}
}
#[cfg(unix)]
#[tokio::test]
async fn regular_file_path_is_not_stale_socket_path() {
let temp_dir = tempfile::TempDir::new().expect("temp dir");
let regular_file = temp_dir.path().join("not-a-socket");
std::fs::write(&regular_file, b"not a socket").expect("regular file should be created");
assert!(
!is_stale_socket_path(&regular_file)
.await
.expect("stale socket check should succeed")
);
}
#[tokio::test]
async fn bound_listener_path_is_stale_socket_path() {
let temp_dir = tempfile::TempDir::new().expect("temp dir");
let socket_path = temp_dir.path().join("socket");
let _listener = match UnixListener::bind(&socket_path).await {
Ok(listener) => listener,
Err(err) if err.kind() == ErrorKind::PermissionDenied => {
eprintln!("skipping test: failed to bind unix socket: {err}");
return;
}
Err(err) => panic!("failed to bind test socket: {err}"),
};
assert!(
is_stale_socket_path(&socket_path)
.await
.expect("stale socket check should succeed")
);
}
#[tokio::test]
async fn stream_round_trips_data_between_listener_and_client() {
let temp_dir = tempfile::TempDir::new().expect("temp dir");
let socket_path = temp_dir.path().join("socket");
let mut listener = match UnixListener::bind(&socket_path).await {
Ok(listener) => listener,
Err(err) if err.kind() == ErrorKind::PermissionDenied => {
eprintln!("skipping test: failed to bind unix socket: {err}");
return;
}
Err(err) => panic!("failed to bind test socket: {err}"),
};
let server_task = tokio::spawn(async move {
let mut server_stream = listener.accept().await.expect("connection should accept");
let mut request = [0; 7];
server_stream
.read_exact(&mut request)
.await
.expect("server should read request");
assert_eq!(&request, b"request");
server_stream
.write_all(b"response")
.await
.expect("server should write response");
});
let mut client_stream = UnixStream::connect(&socket_path)
.await
.expect("client should connect");
client_stream
.write_all(b"request")
.await
.expect("client should write request");
let mut response = [0; 8];
client_stream
.read_exact(&mut response)
.await
.expect("client should read response");
assert_eq!(&response, b"response");
server_task.await.expect("server task should join");
}