Add BrokerPort: loopd asks brokerd for every tool call
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
//! Tests for `BrokerPort` when the broker's frames break the protocol. Every one ends in the same
|
||||
//! plain failure and one printed line. Do not edit.
|
||||
|
||||
#[path = "support/broker.rs"]
|
||||
mod fake;
|
||||
|
||||
use std::io::Write;
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use fake::{assert_unavailable, broker, call, frame, in_ms, request, result, send};
|
||||
use proto::{Envelope, ErrorCode, Message, PROTOCOL_VERSION, ToolResponse, WireError, write_frame};
|
||||
|
||||
#[test]
|
||||
fn frames_that_break_the_protocol_are_unavailable() {
|
||||
type Script = Box<dyn FnOnce(&mut UnixStream, &Envelope) + Send>;
|
||||
let pending = |approval| ToolResponse::PendingApproval {
|
||||
approval,
|
||||
expires: in_ms(60_000),
|
||||
};
|
||||
let cases: Vec<(&str, Script)> = vec![
|
||||
(
|
||||
"an answer for another request id",
|
||||
Box::new(|s, r| send(s, r.id + 1, true, result("x"))),
|
||||
),
|
||||
(
|
||||
"a final frame that is pending",
|
||||
Box::new(move |s, r| send(s, r.id, true, pending(1))),
|
||||
),
|
||||
(
|
||||
"an answer that is not final",
|
||||
Box::new(|s, r| send(s, r.id, false, result("x"))),
|
||||
),
|
||||
(
|
||||
"a second pending frame",
|
||||
Box::new(move |s, r| {
|
||||
send(s, r.id, false, pending(1));
|
||||
send(s, r.id, false, pending(2));
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
}),
|
||||
),
|
||||
(
|
||||
"pending, then another id",
|
||||
Box::new(move |s, r| {
|
||||
send(s, r.id, false, pending(1));
|
||||
send(s, r.id + 1, true, result("x"));
|
||||
}),
|
||||
),
|
||||
(
|
||||
"an error message",
|
||||
Box::new(|s, r| {
|
||||
let error = Message::Error(WireError {
|
||||
code: ErrorCode::Forbidden,
|
||||
detail: "tool requests only".to_string(),
|
||||
});
|
||||
let _ = write_frame(s, &frame(r.id, true, error));
|
||||
}),
|
||||
),
|
||||
(
|
||||
"a message of another kind",
|
||||
Box::new(|s, r| {
|
||||
let echo = Message::ToolRequest(request());
|
||||
let _ = write_frame(s, &frame(r.id, true, echo));
|
||||
}),
|
||||
),
|
||||
(
|
||||
"another protocol version",
|
||||
Box::new(|s, r| {
|
||||
let mut env = frame(r.id, true, Message::ToolResponse(result("x")));
|
||||
env.v = PROTOCOL_VERSION + 1;
|
||||
let _ = write_frame(s, &env);
|
||||
}),
|
||||
),
|
||||
(
|
||||
"a zero length",
|
||||
Box::new(|s, _| {
|
||||
let _ = s.write_all(&[0, 0, 0, 0]);
|
||||
}),
|
||||
),
|
||||
(
|
||||
"a length over the maximum",
|
||||
Box::new(|s, _| {
|
||||
let _ = s.write_all(&[0xff, 0xff, 0xff, 0xff]);
|
||||
}),
|
||||
),
|
||||
(
|
||||
"a body that is not JSON",
|
||||
Box::new(|s, _| {
|
||||
let _ = s.write_all(&[0, 0, 0, 5]);
|
||||
let _ = s.write_all(b"hello");
|
||||
}),
|
||||
),
|
||||
(
|
||||
"a body cut short",
|
||||
Box::new(|s, _| {
|
||||
let _ = s.write_all(&[0, 0, 0, 50]);
|
||||
let _ = s.write_all(b"{\"v\":1");
|
||||
}),
|
||||
),
|
||||
];
|
||||
for (why, script) in cases {
|
||||
let (socket, broker) = broker(script);
|
||||
let got = call(socket, 1_000, &request());
|
||||
assert_unavailable(&got, why);
|
||||
broker.join().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_error_message_the_broker_sent_is_in_the_line() {
|
||||
let (socket, broker) = broker(|s, r| {
|
||||
let error = Message::Error(WireError {
|
||||
code: ErrorCode::Internal,
|
||||
detail: "the ledger is gone".to_string(),
|
||||
});
|
||||
let _ = write_frame(s, &frame(r.id, true, error));
|
||||
});
|
||||
let got = call(socket, 1_000, &request());
|
||||
assert_unavailable(&got, "an error message");
|
||||
assert!(
|
||||
got.lines[0].contains("the ledger is gone"),
|
||||
"{}",
|
||||
got.lines[0]
|
||||
);
|
||||
broker.join().unwrap();
|
||||
}
|
||||
Reference in New Issue
Block a user