mirror of
https://github.com/openai/codex.git
synced 2026-04-27 16:15:09 +00:00
227 lines
6.6 KiB
Rust
227 lines
6.6 KiB
Rust
use std::collections::HashMap;
|
|
|
|
use pretty_assertions::assert_eq;
|
|
|
|
use super::ExecServerHandler;
|
|
use crate::protocol::ExecParams;
|
|
use crate::protocol::ExecSandboxConfig;
|
|
use crate::protocol::ExecSandboxMode;
|
|
use crate::protocol::InitializeParams;
|
|
use crate::protocol::PROTOCOL_VERSION;
|
|
use crate::protocol::TerminateParams;
|
|
use crate::protocol::WriteParams;
|
|
|
|
fn exec_params(process_id: &str) -> ExecParams {
|
|
ExecParams {
|
|
process_id: process_id.to_string(),
|
|
argv: vec![
|
|
"bash".to_string(),
|
|
"-lc".to_string(),
|
|
"sleep 30".to_string(),
|
|
],
|
|
cwd: std::env::current_dir().expect("cwd"),
|
|
env: HashMap::new(),
|
|
tty: false,
|
|
arg0: None,
|
|
sandbox: None,
|
|
}
|
|
}
|
|
|
|
async fn initialized_handler() -> ExecServerHandler {
|
|
let (notification_tx, _notification_rx) = tokio::sync::mpsc::channel(8);
|
|
let mut handler = ExecServerHandler::new(notification_tx, None);
|
|
let response = handler
|
|
.initialize(InitializeParams {
|
|
client_name: "test".to_string(),
|
|
auth_token: None,
|
|
})
|
|
.expect("initialize should succeed");
|
|
assert_eq!(response.protocol_version, PROTOCOL_VERSION);
|
|
handler
|
|
.initialized()
|
|
.expect("initialized notification should succeed");
|
|
handler
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn initialize_reports_protocol_version() {
|
|
let (notification_tx, _notification_rx) = tokio::sync::mpsc::channel(1);
|
|
let mut handler = ExecServerHandler::new(notification_tx, None);
|
|
|
|
let response = handler
|
|
.initialize(InitializeParams {
|
|
client_name: "test".to_string(),
|
|
auth_token: None,
|
|
})
|
|
.expect("initialize should succeed");
|
|
|
|
assert_eq!(response.protocol_version, PROTOCOL_VERSION);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn exec_methods_require_initialize() {
|
|
let (notification_tx, _notification_rx) = tokio::sync::mpsc::channel(1);
|
|
let handler = ExecServerHandler::new(notification_tx, None);
|
|
|
|
let error = handler
|
|
.exec(exec_params("proc-1"))
|
|
.await
|
|
.expect_err("exec should fail before initialize");
|
|
|
|
assert_eq!(error.code, -32600);
|
|
assert_eq!(
|
|
error.message,
|
|
"client must call initialize before using exec methods"
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn exec_methods_require_initialized_notification_after_initialize() {
|
|
let (notification_tx, _notification_rx) = tokio::sync::mpsc::channel(1);
|
|
let mut handler = ExecServerHandler::new(notification_tx, None);
|
|
let _ = handler
|
|
.initialize(InitializeParams {
|
|
client_name: "test".to_string(),
|
|
auth_token: None,
|
|
})
|
|
.expect("initialize should succeed");
|
|
|
|
let error = handler
|
|
.exec(exec_params("proc-1"))
|
|
.await
|
|
.expect_err("exec should fail before initialized notification");
|
|
|
|
assert_eq!(error.code, -32600);
|
|
assert_eq!(
|
|
error.message,
|
|
"client must send initialized before using exec methods"
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn initialized_before_initialize_is_a_protocol_error() {
|
|
let (notification_tx, _notification_rx) = tokio::sync::mpsc::channel(1);
|
|
let mut handler = ExecServerHandler::new(notification_tx, None);
|
|
|
|
let error = handler
|
|
.initialized()
|
|
.expect_err("expected protocol error for early initialized notification");
|
|
|
|
assert_eq!(
|
|
error,
|
|
"received `initialized` notification before `initialize`"
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn initialize_may_only_be_sent_once_per_connection() {
|
|
let (notification_tx, _notification_rx) = tokio::sync::mpsc::channel(1);
|
|
let mut handler = ExecServerHandler::new(notification_tx, None);
|
|
let _ = handler
|
|
.initialize(InitializeParams {
|
|
client_name: "test".to_string(),
|
|
auth_token: None,
|
|
})
|
|
.expect("first initialize should succeed");
|
|
|
|
let error = handler
|
|
.initialize(InitializeParams {
|
|
client_name: "test".to_string(),
|
|
auth_token: None,
|
|
})
|
|
.expect_err("duplicate initialize should fail");
|
|
|
|
assert_eq!(error.code, -32600);
|
|
assert_eq!(
|
|
error.message,
|
|
"initialize may only be sent once per connection"
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn initialize_rejects_invalid_auth_token() {
|
|
let (notification_tx, _notification_rx) = tokio::sync::mpsc::channel(1);
|
|
let mut handler = ExecServerHandler::new(notification_tx, Some("secret-token".to_string()));
|
|
|
|
let error = handler
|
|
.initialize(InitializeParams {
|
|
client_name: "test".to_string(),
|
|
auth_token: Some("wrong-token".to_string()),
|
|
})
|
|
.expect_err("invalid auth token should fail");
|
|
|
|
assert_eq!(error.code, -32001);
|
|
assert_eq!(error.message, "invalid exec-server auth token");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn exec_rejects_host_default_sandbox_mode() {
|
|
let handler = initialized_handler().await;
|
|
|
|
let error = handler
|
|
.exec(ExecParams {
|
|
sandbox: Some(ExecSandboxConfig {
|
|
mode: ExecSandboxMode::HostDefault,
|
|
}),
|
|
..exec_params("proc-1")
|
|
})
|
|
.await
|
|
.expect_err("hostDefault sandbox should be rejected");
|
|
|
|
assert_eq!(error.code, -32600);
|
|
assert_eq!(
|
|
error.message,
|
|
"sandbox mode `hostDefault` is not supported by exec-server yet"
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn exec_rejects_duplicate_process_ids() {
|
|
let handler = initialized_handler().await;
|
|
let first = handler
|
|
.exec(exec_params("proc-1"))
|
|
.await
|
|
.expect("first exec should succeed");
|
|
assert_eq!(first.process_id, "proc-1");
|
|
|
|
let error = handler
|
|
.exec(exec_params("proc-1"))
|
|
.await
|
|
.expect_err("duplicate process id should fail");
|
|
|
|
assert_eq!(error.code, -32600);
|
|
assert_eq!(error.message, "process proc-1 already exists");
|
|
|
|
handler.shutdown().await;
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn write_rejects_unknown_process_ids() {
|
|
let handler = initialized_handler().await;
|
|
|
|
let error = handler
|
|
.write(WriteParams {
|
|
process_id: "missing".to_string(),
|
|
chunk: b"input".to_vec().into(),
|
|
})
|
|
.await
|
|
.expect_err("writing to an unknown process should fail");
|
|
|
|
assert_eq!(error.code, -32600);
|
|
assert_eq!(error.message, "unknown process id missing");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn terminate_reports_missing_processes_as_not_running() {
|
|
let handler = initialized_handler().await;
|
|
|
|
let response = handler
|
|
.terminate(TerminateParams {
|
|
process_id: "missing".to_string(),
|
|
})
|
|
.await
|
|
.expect("terminate should succeed");
|
|
|
|
assert_eq!(response.running, false);
|
|
}
|