mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-08 09:37:47 +03:00
137 lines
5.1 KiB
Rust
137 lines
5.1 KiB
Rust
#![cfg(unix)]
|
|
|
|
use std::process::{Command, Stdio};
|
|
use std::thread;
|
|
use std::time::{Duration, Instant};
|
|
|
|
use opencode_pty::client::TerminalClient;
|
|
use opencode_pty::daemon::{REGISTRATION_FILE, Registration};
|
|
use opencode_pty::protocol::{Envelope, Request, Response, read_frame, write_frame};
|
|
use opencode_pty::service::CreatePty;
|
|
|
|
#[test]
|
|
fn daemon_client_read_rows_roundtrip() {
|
|
// Run the Rust client in a child test process so discovery's environment is
|
|
// isolated without mutating this multithreaded test process's environment.
|
|
if let Some(directory) = std::env::var_os("OPENCODE_PTY_ROWS_TEST_CHILD") {
|
|
let directory = std::path::PathBuf::from(directory);
|
|
let client = TerminalClient::discover(&directory).unwrap();
|
|
let mut request = CreatePty::shell().unwrap();
|
|
request.program = "/bin/sh".to_string();
|
|
request.args = vec!["-c".to_string(), "printf 'one\ntwo\n\nfour\n'".to_string()];
|
|
request.cols = 10;
|
|
request.rows = 3;
|
|
let terminal = client.create_pty(request).unwrap();
|
|
let deadline = Instant::now() + Duration::from_secs(5);
|
|
loop {
|
|
let rows = client.read_rows(terminal.id, None).unwrap();
|
|
if rows.lines == ["", "four", ""] {
|
|
assert_eq!(
|
|
(
|
|
rows.process.pty.as_ref().unwrap().cols,
|
|
rows.process.pty.as_ref().unwrap().rows
|
|
),
|
|
(10, 3)
|
|
);
|
|
assert_eq!((rows.cursor_x, rows.cursor_y), (0, 2));
|
|
break;
|
|
}
|
|
assert!(Instant::now() < deadline, "terminal output not received");
|
|
thread::sleep(Duration::from_millis(10));
|
|
}
|
|
assert_eq!(client.read_rows(terminal.id, Some(1)).unwrap().lines, [""]);
|
|
assert_eq!(
|
|
client.read_rows(terminal.id, Some(5)).unwrap().lines,
|
|
["one", "two", "", "four", ""]
|
|
);
|
|
assert!(
|
|
client
|
|
.read_rows(terminal.id, Some(0))
|
|
.unwrap_err()
|
|
.to_string()
|
|
.contains("positive")
|
|
);
|
|
|
|
let registration = opencode_pty::daemon::read_registration(&directory).unwrap();
|
|
assert_eq!(registration.protocol, 8);
|
|
// Exercise omitted rows independently of the Rust client's null encoding.
|
|
let mut stream = std::os::unix::net::UnixStream::connect(registration.socket).unwrap();
|
|
write_frame(
|
|
&mut stream,
|
|
&serde_json::json!({
|
|
"token": registration.token,
|
|
"request": { "op": "read_rows", "id": terminal.id }
|
|
}),
|
|
)
|
|
.unwrap();
|
|
let response: serde_json::Value = read_frame(&mut stream).unwrap();
|
|
assert_eq!(response["type"], "rows");
|
|
assert_eq!(response["lines"], serde_json::json!(["", "four", ""]));
|
|
assert_eq!(response["process"]["id"], terminal.id);
|
|
assert_eq!(response["cursor_y"], 2);
|
|
client.resize(terminal.id, 12, 4).unwrap();
|
|
let rows = client.read_rows(terminal.id, None).unwrap();
|
|
assert_eq!(rows.lines, ["two", "", "four", ""]);
|
|
assert_eq!(
|
|
(
|
|
rows.process.pty.as_ref().unwrap().cols,
|
|
rows.process.pty.as_ref().unwrap().rows
|
|
),
|
|
(12, 4)
|
|
);
|
|
client.terminate(terminal.id).unwrap();
|
|
return;
|
|
}
|
|
|
|
let root =
|
|
std::env::temp_dir().join(format!("opencode-pty-rows-{:032x}", rand::random::<u128>()));
|
|
let runtime = root.join("rows");
|
|
let mut daemon = Command::new(env!("CARGO_BIN_EXE_opencode-pty"))
|
|
.args(["daemon", "--name", "rows", "--runtime-dir"])
|
|
.arg(&root)
|
|
.stdin(Stdio::null())
|
|
.stdout(Stdio::null())
|
|
.spawn()
|
|
.unwrap();
|
|
let deadline = Instant::now() + Duration::from_secs(10);
|
|
while !runtime.join(REGISTRATION_FILE).exists() && Instant::now() < deadline {
|
|
thread::sleep(Duration::from_millis(10));
|
|
}
|
|
let registration: Registration =
|
|
serde_json::from_slice(&std::fs::read(runtime.join(REGISTRATION_FILE)).unwrap()).unwrap();
|
|
let mut owner = std::os::unix::net::UnixStream::connect(®istration.socket).unwrap();
|
|
write_frame(
|
|
&mut owner,
|
|
&Envelope {
|
|
token: registration.token,
|
|
request: Request::Own {
|
|
instance_id: registration.instance_id,
|
|
ticket: None,
|
|
},
|
|
},
|
|
)
|
|
.unwrap();
|
|
assert!(matches!(
|
|
read_frame::<Response>(&mut owner).unwrap(),
|
|
Response::Owned
|
|
));
|
|
let result = Command::new(std::env::current_exe().unwrap())
|
|
.args([
|
|
"--exact",
|
|
"daemon_client_read_rows_roundtrip",
|
|
"--nocapture",
|
|
])
|
|
.env("OPENCODE_PTY_ROWS_TEST_CHILD", &runtime)
|
|
.output();
|
|
drop(owner);
|
|
assert!(daemon.wait().unwrap().success());
|
|
let _ = std::fs::remove_dir_all(root);
|
|
let output = result.unwrap();
|
|
assert!(
|
|
output.status.success(),
|
|
"{}\n{}",
|
|
String::from_utf8_lossy(&output.stdout),
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
}
|