Return chunked body data as soon as it is available

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
This commit is contained in:
2026-09-18 16:15:22 -07:00
parent 1faa38be44
commit 0f5213a466
3 changed files with 45 additions and 5 deletions
+43
View File
@@ -308,3 +308,46 @@ fn a_missing_socket_is_a_connect_error() {
let e: Box<dyn std::error::Error> = Box::new(HttpError::Timeout);
assert!(!e.to_string().is_empty());
}
/// A streamed body is read while it arrives. A `read` that already has data must not block
/// waiting for more, or every event is delivered one buffer late and the last ones only when
/// the stream ends.
#[test]
fn streamed_data_is_delivered_as_it_arrives() {
let server = FakeServer::start();
let reply = Reply::fixture("turn1");
let piece = reply.offset_after_events(1);
// About one event per piece, 300 ms apart: the whole stream takes over a second.
server.route("/v1/chat/completions", vec![reply.trickle(piece, 300)]);
let mut conn = Connection::open(&server.socket).unwrap();
conn.set_read_timeout(Duration::from_secs(5)).unwrap();
conn.send(&Request {
method: "POST",
path: "/v1/chat/completions",
body: Some(b"{}"),
})
.unwrap();
let head = conn.read_head().unwrap();
let started = std::time::Instant::now();
let mut body = conn.body(&head).unwrap();
let mut arrivals = Vec::new();
let mut buf = [0u8; 8192];
loop {
let n = std::io::Read::read(&mut body, &mut buf).unwrap();
if n == 0 {
break;
}
arrivals.push(started.elapsed());
}
let first = arrivals.first().copied().unwrap_or_default();
let last = arrivals.last().copied().unwrap_or_default();
assert!(
first < Duration::from_millis(200),
"the first data came only after {first:?}"
);
assert!(
last - first >= Duration::from_millis(600),
"everything arrived within {:?} of the first read: the reader is buffering the stream",
last - first
);
}