Skip to content

Commit c72280c

Browse files
committed
Test stream idle timeout coordination
1 parent 0bc195f commit c72280c

2 files changed

Lines changed: 59 additions & 0 deletions

File tree

crates/fluxheim-stream/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@ fluxheim-config = { path = "../fluxheim-config", features = ["stream-proxy"] }
1313
fluxheim-protocol = { path = "../fluxheim-protocol" }
1414
sanitization = { version = "1.2.4" }
1515
tokio = { version = "1.52.3", features = ["io-util", "macros", "rt", "sync", "time"] }
16+
17+
[dev-dependencies]
18+
tokio = { version = "1.52.3", features = ["test-util"] }

crates/fluxheim-stream/src/stream_tests.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,62 @@ async fn stream_copy_preserves_both_directions_under_partial_write_backpressure(
285285
assert_eq!(server_result.unwrap(), downstream_payload);
286286
}
287287

288+
#[tokio::test(start_paused = true)]
289+
async fn stream_copy_one_way_activity_keeps_shared_idle_deadline_alive() {
290+
const IDLE_TIMEOUT: Duration = Duration::from_secs(10);
291+
const ACTIVITY_INTERVAL: Duration = Duration::from_secs(8);
292+
293+
let (mut downstream_proxy, downstream_client) = tokio::io::duplex(16);
294+
let (mut upstream_proxy, upstream_server) = tokio::io::duplex(16);
295+
let copy = copy_bidirectional_with_limits(
296+
&mut downstream_proxy,
297+
&mut upstream_proxy,
298+
IDLE_TIMEOUT,
299+
None,
300+
);
301+
let traffic = async move {
302+
let (mut downstream_reader, mut downstream_writer) = tokio::io::split(downstream_client);
303+
let (mut upstream_reader, mut upstream_writer) = tokio::io::split(upstream_server);
304+
upstream_writer.shutdown().await?;
305+
306+
for byte in b"alive" {
307+
downstream_writer.write_all(&[*byte]).await?;
308+
tokio::task::yield_now().await;
309+
tokio::time::advance(ACTIVITY_INTERVAL).await;
310+
}
311+
downstream_writer.shutdown().await?;
312+
313+
let mut forwarded = Vec::new();
314+
upstream_reader.read_to_end(&mut forwarded).await?;
315+
let mut reverse = Vec::new();
316+
downstream_reader.read_to_end(&mut reverse).await?;
317+
Ok::<_, io::Error>((forwarded, reverse))
318+
};
319+
320+
let (copy_result, traffic_result) = tokio::join!(copy, traffic);
321+
assert_eq!(copy_result.unwrap(), (5, 0));
322+
assert_eq!(traffic_result.unwrap(), (b"alive".to_vec(), Vec::new()));
323+
}
324+
325+
#[tokio::test(start_paused = true)]
326+
async fn stream_copy_true_idle_returns_timeout() {
327+
let (mut downstream_proxy, _downstream_client) = tokio::io::duplex(16);
328+
let (mut upstream_proxy, _upstream_server) = tokio::io::duplex(16);
329+
let idle_timeout = Duration::from_secs(10);
330+
let copy = copy_bidirectional_with_limits(
331+
&mut downstream_proxy,
332+
&mut upstream_proxy,
333+
idle_timeout,
334+
None,
335+
);
336+
let advance_past_deadline = async {
337+
tokio::time::advance(idle_timeout + Duration::from_secs(1)).await;
338+
};
339+
340+
let (copy_result, ()) = tokio::join!(copy, advance_past_deadline);
341+
assert!(matches!(copy_result, Err(FluxError::Timeout { .. })));
342+
}
343+
288344
async fn exchange_duplex_payload(
289345
stream: tokio::io::DuplexStream,
290346
payload: Vec<u8>,

0 commit comments

Comments
 (0)