use super::*;
use crate::reader::SkillMessageReader;
#[tokio::test]
async fn write_and_read_roundtrip() {
let (client, server) = tokio::io::duplex(4096);
let mut writer = SkillMessageWriter::new(client);
let mut reader = SkillMessageReader::new(server);
let payload = AckPayload {
id: "test-1".into(),
accepted: true,
};
writer.write_ack(&payload).await.unwrap();
drop(writer);
let msg = reader.read_message().await.unwrap().unwrap();
assert_eq!(msg.msg_type, SkillMessageType::Ack);
let parsed: AckPayload = msg.deserialize_payload().unwrap();
assert_eq!(parsed.id, "test-1");
assert!(parsed.accepted);
}
#[tokio::test]
async fn write_and_read_execute() {
let (client, server) = tokio::io::duplex(4096);
let mut writer = SkillMessageWriter::new(client);
let mut reader = SkillMessageReader::new(server);
let payload = ExecutePayload {
execution_id: "exec-1".into(),
command_name: "test:exec".into(),
command: Some("ls -la".into()),
args: None,
working_directory: None,
environment: None,
timeout_ms: 30000,
};
writer.write_execute(&payload).await.unwrap();
drop(writer);
let msg = reader.read_message().await.unwrap().unwrap();
assert_eq!(msg.msg_type, SkillMessageType::Execute);
let parsed: ExecutePayload = msg.deserialize_payload().unwrap();
assert_eq!(parsed.execution_id, "exec-1");
assert_eq!(parsed.command.as_deref(), Some("ls -la"));
}
#[tokio::test]
async fn write_and_read_proxy_submit() {
let (client, server) = tokio::io::duplex(4096);
let mut writer = SkillMessageWriter::new(client);
let mut reader = SkillMessageReader::new(server);
let payload = ProxySubmitPayload {
proxy_id: "proxy-1".into(),
external_id: "ext-1".into(),
command_name: "test:exec".into(),
args: vec!["--flag".into(), "value".into()],
target: ProxyTarget {
kind: "local".into(),
agent_id: None,
},
};
writer.write_proxy_submit(&payload).await.unwrap();
drop(writer);
let msg = reader.read_message().await.unwrap().unwrap();
assert_eq!(msg.msg_type, SkillMessageType::ProxySubmit);
assert_eq!(msg.msg_type as u32, 200);
let parsed: ProxySubmitPayload = msg.deserialize_payload().unwrap();
assert_eq!(parsed.proxy_id, "proxy-1");
assert_eq!(parsed.external_id, "ext-1");
assert_eq!(parsed.command_name, "test:exec");
assert_eq!(parsed.args, vec!["--flag", "value"]);
assert_eq!(parsed.target.kind, "local");
}
#[tokio::test]
async fn write_and_read_proxy_cancel() {
let (client, server) = tokio::io::duplex(4096);
let mut writer = SkillMessageWriter::new(client);
let mut reader = SkillMessageReader::new(server);
writer.write_proxy_cancel("proxy-1").await.unwrap();
drop(writer);
let msg = reader.read_message().await.unwrap().unwrap();
assert_eq!(msg.msg_type, SkillMessageType::ProxyCancel);
assert_eq!(msg.msg_type as u32, 201);
assert_eq!(msg.payload, b"proxy-1");
}
#[tokio::test]
async fn write_and_read_proxy_stdout_chunk() {
let (client, server) = tokio::io::duplex(4096);
let mut writer = SkillMessageWriter::new(client);
let mut reader = SkillMessageReader::new(server);
let payload = ProxyChunkPayload {
proxy_id: "proxy-1".into(),
seq: 1,
data: b"out".to_vec(),
};
writer.write_proxy_stdout_chunk(&payload).await.unwrap();
drop(writer);
let msg = reader.read_message().await.unwrap().unwrap();
assert_eq!(msg.msg_type, SkillMessageType::ProxyStdoutChunk);
assert_eq!(msg.msg_type as u32, 202);
let parsed: ProxyChunkPayload = msg.deserialize_payload().unwrap();
assert_eq!(parsed.proxy_id, "proxy-1");
assert_eq!(parsed.seq, 1);
assert_eq!(parsed.data, b"out");
}
#[tokio::test]
async fn write_and_read_proxy_stderr_chunk() {
let (client, server) = tokio::io::duplex(4096);
let mut writer = SkillMessageWriter::new(client);
let mut reader = SkillMessageReader::new(server);
let payload = ProxyChunkPayload {
proxy_id: "proxy-1".into(),
seq: 2,
data: b"err".to_vec(),
};
writer.write_proxy_stderr_chunk(&payload).await.unwrap();
drop(writer);
let msg = reader.read_message().await.unwrap().unwrap();
assert_eq!(msg.msg_type, SkillMessageType::ProxyStderrChunk);
assert_eq!(msg.msg_type as u32, 203);
let parsed: ProxyChunkPayload = msg.deserialize_payload().unwrap();
assert_eq!(parsed.proxy_id, "proxy-1");
assert_eq!(parsed.seq, 2);
assert_eq!(parsed.data, b"err");
}
#[tokio::test]
async fn write_and_read_proxy_completed() {
let (client, server) = tokio::io::duplex(4096);
let mut writer = SkillMessageWriter::new(client);
let mut reader = SkillMessageReader::new(server);
let payload = ProxyCompletedPayload {
proxy_id: "proxy-1".into(),
exit_code: 0,
status: "success".into(),
error: None,
finished_at_unix: 1700000000,
};
writer.write_proxy_completed(&payload).await.unwrap();
drop(writer);
let msg = reader.read_message().await.unwrap().unwrap();
assert_eq!(msg.msg_type, SkillMessageType::ProxyCompleted);
assert_eq!(msg.msg_type as u32, 204);
let parsed: ProxyCompletedPayload = msg.deserialize_payload().unwrap();
assert_eq!(parsed.proxy_id, "proxy-1");
assert_eq!(parsed.exit_code, 0);
assert_eq!(parsed.status, "success");
assert_eq!(parsed.finished_at_unix, 1700000000);
}
#[tokio::test]
async fn write_and_read_proxy_rejected() {
let (client, server) = tokio::io::duplex(4096);
let mut writer = SkillMessageWriter::new(client);
let mut reader = SkillMessageReader::new(server);
let payload = ProxyRejectedPayload {
proxy_id: "proxy-1".into(),
reason_code: "DENIED".into(),
message: "not allowed".into(),
};
writer.write_proxy_rejected(&payload).await.unwrap();
drop(writer);
let msg = reader.read_message().await.unwrap().unwrap();
assert_eq!(msg.msg_type, SkillMessageType::ProxyRejected);
assert_eq!(msg.msg_type as u32, 205);
let parsed: ProxyRejectedPayload = msg.deserialize_payload().unwrap();
assert_eq!(parsed.proxy_id, "proxy-1");
assert_eq!(parsed.reason_code, "DENIED");
assert_eq!(parsed.message, "not allowed");
}