#![allow(clippy::items_after_statements)]
#![allow(clippy::too_many_lines)]
use std::time::{Duration, Instant};
use super::*;
use super::stream_id::{Dir, StreamId};
use super::streams::StreamRef;
use crate::constants::{
FINAL_SIZE_ERROR, FLOW_CONTROL_ERROR, INITIAL_MAX_DATA, INITIAL_MAX_STREAM_DATA,
INITIAL_MAX_STREAMS_BIDI, INITIAL_MAX_STREAMS_UNI, MAX_DATAGRAM, MAX_PLAINTEXT,
PROTOCOL_VIOLATION, REASSEMBLY_CHUNKS_MAX, STREAM_LIMIT_ERROR, STREAM_STATE_ERROR,
STREAMS_CREDIT_BATCH,
};
use crate::core::{Install, Role};
use crate::error::{ReadError, WriteError};
use crate::packet::ReferenceSuite;
use crate::varint::VarInt;
type Suite = ReferenceSuite;
use super::testfix::*;
mod precursors {
use super::*;
#[test]
fn s12_precursor_two_cores_exchange_a_finished_stream() {
let t = t0();
let mut p = Pair::installed_at(t);
let r =
p.a.open(Dir::Uni)
.expect("the first uni stream fits the limit");
let payload = ramp(0, 64 * 1024);
assert!(
payload.len() > MAX_PLAINTEXT * 8,
"a single-packet S12 tests nothing in §9.5"
);
let blocked = write_all(&mut p.a, t, r, &payload);
assert_eq!(
blocked, 0,
"64 KiB is well inside both initial windows; a block here is a \
ledger that grants nothing"
);
p.a.finish(t, r).expect("finish");
let (_, db) = p.pump(t);
assert_eq!(
db.count_events(|e| matches!(e, ConnEvent::StreamOpened { dir: Dir::Uni })),
1,
"§9.2: one stream was opened, so one event (ruling 99)"
);
let rb =
p.b.accept(Dir::Uni)
.expect("the peer-opened stream is claimable");
assert_eq!(
p.b.accept(Dir::Uni),
None,
"only one stream was opened, so only one is claimable"
);
let (got, eof) = read_available(&mut p.b, t, rb);
assert_eq!(got.len(), payload.len(), "every byte, exactly once");
assert_eq!(got, payload, "the same bytes, in the same order");
assert!(eof, "finish() delivered the FIN, so the reader sees EOF");
assert_eq!(
p.b.read(t, rb, &mut [0u8; 16]),
Ok(None),
"end of stream stays end of stream"
);
}
#[test]
fn s13_precursor_two_streams_reassemble_independently() {
let t = t0();
let mut s = Solo::installed_at(t);
let a = Solo::peer_uni(0);
let b = Solo::peer_uni(1);
let d = s.deliver(t, &stream_frame(b, 0, &ramp(0, 512), true));
assert_alive(&d);
assert_eq!(
d.count_events(|e| matches!(e, ConnEvent::StreamOpened { dir: Dir::Uni })),
2,
"§9.2: naming index 1 opens 0 and 1 — two streams, two events"
);
let claimed = accept_all(&mut s.conn, Dir::Uni);
assert_eq!(
claimed.iter().map(|(id, _)| *id).collect::<Vec<_>>(),
vec![a, b],
"both implicitly-opened indices are claimable"
);
let r0 = claimed[0].1;
let r1 = claimed[1].1;
let (got_b, eof_b) = read_available(&mut s.conn, t, r1);
assert_eq!(got_b, ramp(0, 512), "B is readable while A is missing");
assert!(eof_b, "B's FIN arrived, so B is at end of stream");
let (got_a, eof_a) = read_available(&mut s.conn, t, r0);
assert!(
got_a.is_empty() && !eof_a,
"A has no data and no FIN: it must park, not report EOF"
);
let _ = s.deliver(t, &stream_frame(a, 256, &ramp(256, 256), true));
let _ = s.deliver(t, &stream_frame(a, 0, &ramp(0, 256), false));
let (got_a, eof_a) = read_available(&mut s.conn, t, r0);
assert_eq!(got_a, ramp(0, 512), "A reassembles independently of B");
assert!(eof_a);
}
#[test]
fn s17_precursor_the_credit_ledger_stalls_and_resumes() {
let t = t0();
let mut p = Pair::installed_at(t);
let r = p.a.open(Dir::Uni).expect("open");
let at = write_until_blocked(&mut p.a, t, r);
assert_eq!(
at, INITIAL_MAX_STREAM_DATA,
"§10.2: the writer stalls at the peer's initial stream window, \
not before it and not past it"
);
let (_, _) = p.pump(t);
let rb = p.b.accept(Dir::Uni).expect("the stream opened at the peer");
let half = (INITIAL_MAX_STREAM_DATA / 2) as usize;
let _ = read_exactly(&mut p.b, t, rb, half - 1);
let (_, _) = p.pump(t);
assert_eq!(
p.a.write(t, r, &[0u8; 1]).expect("write"),
0,
"§10.3: below WINDOW/2 consumed, no credit is re-granted"
);
let _ = read_exactly(&mut p.b, t, rb, 1);
let (_, _) = p.pump(t);
let more = write_until_blocked(&mut p.a, t, r);
assert_eq!(
more,
INITIAL_MAX_STREAM_DATA / 2,
"§10.3's re-grant is absolute — `bytes_read + WINDOW` — so the \
writer gains exactly the bytes the reader consumed"
);
}
}
mod identifiers {
use super::*;
#[test]
fn stream_ids_carry_the_role_from_install_not_from_who_created_the_core() {
let t = t0();
let mut p = Pair::installed_at(t);
assert_eq!(p.a.role(), Some(Role::Initiator));
assert_eq!(p.b.role(), Some(Role::Responder));
let a_uni = p.a.open(Dir::Uni).expect("open");
let b_uni = p.b.open(Dir::Uni).expect("open");
let a_bi = p.a.open(Dir::Bi).expect("open");
let b_bi = p.b.open(Dir::Bi).expect("open");
let id = |c: &Connection<Suite>, r| c.stream_id(r).expect("established").as_u64();
assert_eq!(id(&p.a, a_uni), 2, "initiator uni index 0 = 0<<2 | 0x02");
assert_eq!(id(&p.b, b_uni), 3, "acceptor uni index 0 = 0<<2 | 0x03");
assert_eq!(id(&p.a, a_bi), 0, "initiator bidi index 0 = 0");
assert_eq!(id(&p.b, b_bi), 1, "acceptor bidi index 0 = 1");
assert_eq!(id(&p.a, a_uni) & 0x01, 0, "§9.1: the dialler's parity");
assert_eq!(id(&p.b, b_uni) & 0x01, 1, "§9.1: the acceptor's parity");
assert!(
p.a.stream_id(a_uni)
.expect("established")
.initiated_by_connection_initiator()
);
assert!(
!p.b.stream_id(b_uni)
.expect("established")
.initiated_by_connection_initiator()
);
}
#[test]
fn the_two_bit_tag_places_index_direction_and_opener_where_9_1_says() {
assert_eq!(raw_id(0, Dir::Bi, true), 0);
assert_eq!(raw_id(0, Dir::Bi, false), 1);
assert_eq!(raw_id(0, Dir::Uni, true), 2);
assert_eq!(raw_id(0, Dir::Uni, false), 3);
assert_eq!(raw_id(7, Dir::Uni, true), 30, "7 << 2 | 0x02");
for &(index, dir, init) in &[
(0u64, Dir::Bi, true),
(1, Dir::Uni, false),
(999, Dir::Bi, false),
((1u64 << 60) - 1, Dir::Uni, true),
] {
let id = StreamId::from_u64(raw_id(index, dir, init));
assert_eq!(id.index(), index, "§9.1: index is the id shifted by 2");
assert_eq!(id.dir(), dir);
assert_eq!(id.initiated_by_connection_initiator(), init);
assert_eq!(id.as_u64(), raw_id(index, dir, init));
}
}
#[test]
fn the_index_ceiling_is_two_to_the_sixty_not_the_varint_ceiling() {
let top = StreamId::from_u64(VarInt::MAX_VALUE);
assert_eq!(
top.index(),
(1u64 << 60) - 1,
"§9.1: 60 bits of index under a 62-bit varint"
);
assert_eq!(top.as_u64(), VarInt::MAX_VALUE, "total, and lossless");
}
#[test]
fn each_space_allocates_indices_from_zero_independently() {
let t = t0();
let mut p = Pair::installed_at(t);
let bi: Vec<u64> = (0..3)
.map(|_| {
let r = p.a.open(Dir::Bi).expect("open");
p.a.stream_id(r).expect("established").index()
})
.collect();
let uni: Vec<u64> = (0..3)
.map(|_| {
let r = p.a.open(Dir::Uni).expect("open");
p.a.stream_id(r).expect("established").index()
})
.collect();
assert_eq!(bi, vec![0, 1, 2], "the bidi space counts from 0");
assert_eq!(uni, vec![0, 1, 2], "so does the uni space, separately");
}
}
mod early_sends {
use super::*;
#[test]
fn an_early_opened_stream_keeps_its_handle_across_install() {
let t = t0();
let mut p = Pair::unestablished();
let r =
p.a.open(Dir::Uni)
.expect("§16.9: open() before install is legal");
assert_eq!(
p.a.stream_id(r),
None,
"§16.9: the wire id does not exist until establishment"
);
let early = ramp(0, 4096);
assert_eq!(
write_all(&mut p.a, t, r, &early),
0,
"early writes are ordinary work"
);
let d = p.drain_a();
assert!(
d.transmits().is_empty(),
"§16.9: no frame is emitted before install — nothing can send \
without a session"
);
p.install(t);
let _ = p.drain_a();
let _ = p.drain_b();
assert_eq!(
p.a.stream_id(r).map(StreamId::as_u64),
Some(2),
"on install the internal index maps onto the parity the \
outcome dictated"
);
let late = ramp(4096, 4096);
assert_eq!(write_all(&mut p.a, t, r, &late), 0);
p.a.finish(t, r).expect("finish");
let _ = p.pump(t);
let rb =
p.b.accept(Dir::Uni)
.expect("exactly one stream reached the peer");
assert_eq!(
p.b.accept(Dir::Uni),
None,
"a remap that opened a second stream would show up here"
);
let (got, eof) = read_available(&mut p.b, t, rb);
assert_eq!(
got,
ramp(0, 8192),
"§16.9: delivered exactly once, in order"
);
assert!(eof);
}
#[test]
fn stream_id_is_none_before_establishment_and_some_after() {
let t = t0();
let mut p = Pair::unestablished();
let r = p.a.open(Dir::Bi).expect("open");
assert_eq!(p.a.stream_id(r), None);
p.install(t);
let _ = p.drain_a();
assert_eq!(p.a.stream_id(r).map(StreamId::as_u64), Some(0));
}
}
mod implicit_opening {
use super::*;
#[test]
fn an_implicit_open_of_six_streams_emits_six_stream_opened_events() {
let t = t0();
let mut s = Solo::installed_at(t);
let d = s.deliver(t, &stream_frame(Solo::peer_uni(5), 0, &ramp(0, 8), false));
assert_alive(&d);
assert_eq!(
d.count_events(|e| matches!(e, ConnEvent::StreamOpened { dir: Dir::Uni })),
6,
"§9.2: index 5 opens 0..=5 — six streams, so six events"
);
assert_eq!(
d.count_events(|e| matches!(e, ConnEvent::StreamOpened { dir: Dir::Bi })),
0,
"the four spaces are independent: no bidi stream was opened"
);
let claimed = accept_all(&mut s.conn, Dir::Uni);
assert_eq!(
claimed.iter().map(|(id, _)| *id).collect::<Vec<_>>(),
(0..6).map(Solo::peer_uni).collect::<Vec<_>>(),
"every implicitly-opened index is claimable, and only those"
);
}
#[test]
fn a_frame_above_the_cumulative_limit_emits_zero_events_before_the_kill() {
let t = t0();
let mut s = Solo::installed_at(t);
let over = Solo::peer_uni(INITIAL_MAX_STREAMS_UNI);
let d = s.deliver(t, &stream_frame(over, 0, &ramp(0, 8), false));
let frames = s.drain_frames(&d);
assert_eq!(
d.count_events(|e| matches!(e, ConnEvent::StreamOpened { .. })),
0,
"ruling 99: §10.4's limit check runs before the opens it would \
authorise, so not one event escapes"
);
assert_violation(&d, &frames, STREAM_LIMIT_ERROR);
}
#[test]
fn uni_index_127_opens_and_128_is_a_stream_limit_error() {
let t = t0();
let mut alive = Solo::installed_at(t);
let last = Solo::peer_uni(INITIAL_MAX_STREAMS_UNI - 1);
let d = alive.deliver(t, &stream_frame(last, 0, &ramp(0, 4), false));
assert_alive(&d);
assert_eq!(
d.count_events(|e| matches!(e, ConnEvent::StreamOpened { dir: Dir::Uni })),
INITIAL_MAX_STREAMS_UNI as usize,
"index 127 opens exactly 128 streams — the whole allowance"
);
let mut dead = Solo::installed_at(t);
let over = Solo::peer_uni(INITIAL_MAX_STREAMS_UNI);
let d = dead.deliver(t, &stream_frame(over, 0, &ramp(0, 4), false));
let frames = dead.drain_frames(&d);
assert_violation(&d, &frames, STREAM_LIMIT_ERROR);
}
#[test]
fn bidi_index_31_opens_and_32_is_a_stream_limit_error() {
let t = t0();
let mut alive = Solo::installed_at(t);
let last = Solo::peer_bidi(INITIAL_MAX_STREAMS_BIDI - 1);
let d = alive.deliver(t, &stream_frame(last, 0, &ramp(0, 4), false));
assert_alive(&d);
assert_eq!(
d.count_events(|e| matches!(e, ConnEvent::StreamOpened { dir: Dir::Bi })),
INITIAL_MAX_STREAMS_BIDI as usize
);
let mut dead = Solo::installed_at(t);
let over = Solo::peer_bidi(INITIAL_MAX_STREAMS_BIDI);
let d = dead.deliver(t, &stream_frame(over, 0, &ramp(0, 4), false));
let frames = dead.drain_frames(&d);
assert_violation(&d, &frames, STREAM_LIMIT_ERROR);
}
#[test]
fn the_first_stream_frame_naming_index_zero_opens_it_and_delivers() {
let t = t0();
let mut s = Solo::installed_at(t);
let d = s.deliver(t, &stream_frame(Solo::peer_uni(0), 0, &ramp(0, 16), true));
assert_alive(&d);
assert_eq!(
d.count_events(|e| matches!(e, ConnEvent::StreamOpened { dir: Dir::Uni })),
1,
"index 0 is a stream like any other, not a tombstone"
);
let r = s.conn.accept(Dir::Uni).expect("index 0 is claimable");
let (got, eof) = read_available(&mut s.conn, t, r);
assert_eq!(got, ramp(0, 16));
assert!(eof);
}
#[test]
fn an_empty_finless_stream_frame_opens_its_stream() {
let t = t0();
let mut s = Solo::installed_at(t);
let d = s.deliver(t, &stream_frame(Solo::peer_uni(0), 0, &[], false));
assert_alive(&d);
assert_eq!(
d.count_events(|e| matches!(e, ConnEvent::StreamOpened { dir: Dir::Uni })),
1,
"ruling 100: §9.2's rule is about the frame, not the payload"
);
assert!(
s.conn.accept(Dir::Uni).is_some(),
"the opened stream is claimable"
);
}
#[test]
fn an_empty_finless_stream_frame_pins_nothing_and_delivers_nothing() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let _ = s.deliver(t, &stream_frame(id, 0, &[], false));
let r = s.conn.accept(Dir::Uni).expect("open");
let (got, eof) = read_available(&mut s.conn, t, r);
assert!(got.is_empty(), "no bytes were delivered");
assert!(
!eof,
"§9.5: no FIN, so no final size — the reader parks (`Ok(Some(0))`), \
it does not see end of stream"
);
assert_eq!(
s.conn.reassembly_capacity(),
0,
"ruling 94: nothing arrived, so nothing is allocated"
);
let d = s.deliver(t, &stream_frame(id, 0, &ramp(0, 10), true));
assert_alive(&d);
let (got, eof) = read_available(&mut s.conn, t, r);
assert_eq!(got, ramp(0, 10), "the empty frame pinned no final size");
assert!(eof);
}
}
mod check_order {
use super::*;
#[test]
fn a_stream_frame_on_a_closed_local_uni_space_is_a_state_error() {
let t = t0();
let mut s = Solo::installed_at(t);
let d = s.deliver(t, &stream_frame(Solo::our_uni(0), 0, &ramp(0, 4), false));
let frames = s.drain_frames(&d);
assert_eq!(
d.count_events(|e| matches!(e, ConnEvent::StreamOpened { .. })),
0,
"an illegal frame opens nothing"
);
assert_violation(&d, &frames, STREAM_STATE_ERROR);
}
#[test]
fn legality_is_checked_before_the_cumulative_limit() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::our_uni(INITIAL_MAX_STREAMS_UNI + 500);
let d = s.deliver(t, &stream_frame(id, 0, &ramp(0, 4), false));
let frames = s.drain_frames(&d);
assert_violation(&d, &frames, STREAM_STATE_ERROR);
}
#[test]
fn legality_is_checked_before_flow_control() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::our_uni(0);
let d = s.deliver(
t,
&stream_frame(id, INITIAL_MAX_STREAM_DATA + 1, &ramp(0, 4), false),
);
let frames = s.drain_frames(&d);
assert_violation(&d, &frames, STREAM_STATE_ERROR);
}
#[test]
fn the_cumulative_limit_is_checked_before_flow_control() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(INITIAL_MAX_STREAMS_UNI);
let d = s.deliver(
t,
&stream_frame(id, INITIAL_MAX_STREAM_DATA + 1, &ramp(0, 4), false),
);
let frames = s.drain_frames(&d);
assert_violation(&d, &frames, STREAM_LIMIT_ERROR);
}
#[test]
fn the_final_size_is_checked_before_flow_control() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let d = s.deliver(t, &stream_frame(id, 0, &ramp(0, 100), true));
assert_alive(&d);
let d = s.deliver(
t,
&stream_frame(id, INITIAL_MAX_STREAM_DATA + 1, &ramp(0, 4), false),
);
let frames = s.drain_frames(&d);
assert_violation(&d, &frames, FINAL_SIZE_ERROR);
}
#[test]
fn a_frame_below_the_watermark_beyond_credit_is_a_no_op_not_a_violation() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let _ = s.deliver(t, &stream_frame(id, 0, &ramp(0, 16), false));
let r = s.conn.accept(Dir::Uni).expect("open");
abandon_recv(&mut s.conn, t, r);
let _ = drain(&mut s.conn);
let d = s.deliver(
t,
&stream_frame(id, INITIAL_MAX_STREAM_DATA * 4, &ramp(0, 64), false),
);
assert_alive(&d);
assert_eq!(
d.count_events(|e| matches!(e, ConnEvent::StreamOpened { .. })),
0,
"§9.2: never re-opened"
);
}
}
mod abandonment {
use super::*;
fn max_datas(s: &mut Solo, d: &Drained) -> Vec<u64> {
s.drain_frames(d)
.into_iter()
.filter_map(|f| match f {
Wire::MaxData(m) => Some(m),
_ => None,
})
.collect()
}
fn two_thin_uni_streams(t: Instant) -> (Solo, StreamRef, StreamRef) {
let mut s = Solo::installed_at(t);
let _ = s.deliver(
t,
&stream_frame(Solo::peer_uni(1), 0, &ramp(0, 1000), false),
);
let _ = s.deliver(
t,
&stream_frame(Solo::peer_uni(0), 0, &ramp(0, 1000), false),
);
let claimed = accept_all(&mut s.conn, Dir::Uni);
assert_eq!(claimed.len(), 2);
let (r0, r1) = (claimed[0].1, claimed[1].1);
let _ = drain(&mut s.conn);
(s, r0, r1)
}
#[test]
fn a_dropped_recv_stream_releases_connection_credit_at_once() {
let t = t0();
let (mut s, r0, r1) = two_thin_uni_streams(t);
abandon_recv(&mut s.conn, t, r0);
let d = drain(&mut s.conn);
let first = max_datas(&mut s, &d);
abandon_recv(&mut s.conn, t, r1);
let d = drain(&mut s.conn);
let second = max_datas(&mut s, &d);
assert!(
first.is_empty(),
"one abandoned stream releases 256 KiB, half of §10.3's \
512 KiB trigger: nothing is owed yet"
);
assert_eq!(
second.len(),
1,
"the second abandonment crosses the trigger **in its own \
drain** — no peer frame intervened, so nothing but the \
abandonment can have caused it"
);
}
#[test]
fn a_dropped_recv_stream_trues_up_to_the_stream_window_not_the_high_water_mark() {
let t = t0();
let (mut s, r0, r1) = two_thin_uni_streams(t);
abandon_recv(&mut s.conn, t, r0);
let d = drain(&mut s.conn);
assert!(max_datas(&mut s, &d).is_empty());
abandon_recv(&mut s.conn, t, r1);
let d = drain(&mut s.conn);
let grants = max_datas(&mut s, &d);
let consumed = 2 * INITIAL_MAX_STREAM_DATA;
assert_eq!(
consumed,
INITIAL_MAX_DATA / 2,
"the arithmetic this rests on"
);
assert_eq!(
grants,
vec![consumed + INITIAL_MAX_DATA],
"§10.3: the prospective limit is `consumed + WINDOW`, and \
consumption for an abandoned half is the stream window it \
advertised — not the 1 000 bytes that happened to arrive"
);
}
#[test]
fn abandoning_peer_opened_uni_halves_fully_closes_them_and_grants_max_streams() {
let t = t0();
let mut s = Solo::installed_at(t);
let batch = STREAMS_CREDIT_BATCH;
let _ = s.deliver(
t,
&stream_frame(Solo::peer_uni(batch - 1), 0, &ramp(0, 8), false),
);
let claimed = accept_all(&mut s.conn, Dir::Uni);
assert_eq!(claimed.len(), batch as usize, "§9.2 opened the whole run");
let _ = drain(&mut s.conn);
let grants = |s: &mut Solo, d: &Drained| -> Vec<u64> {
s.drain_frames(d)
.into_iter()
.filter_map(|f| match f {
Wire::MaxStreamsUni(m) => Some(m),
_ => None,
})
.collect()
};
for (_, r) in claimed.iter().take(batch as usize - 1) {
abandon_recv(&mut s.conn, t, *r);
let d = drain(&mut s.conn);
assert!(
grants(&mut s, &d).is_empty(),
"§10.4 batches: fewer than STREAMS_CREDIT_BATCH grants are \
unadvertised, so nothing goes out"
);
}
abandon_recv(&mut s.conn, t, claimed[batch as usize - 1].1);
let d = drain(&mut s.conn);
assert_eq!(
grants(&mut s, &d),
vec![INITIAL_MAX_STREAMS_UNI + batch],
"§10.4: cumulative, and +1 per fully-closed peer-opened stream"
);
}
#[test]
fn abandoning_bidi_receive_halves_grants_no_max_streams() {
let t = t0();
let mut s = Solo::installed_at(t);
let batch = STREAMS_CREDIT_BATCH;
let _ = s.deliver(
t,
&stream_frame(Solo::peer_bidi(batch - 1), 0, &ramp(0, 8), false),
);
let claimed = accept_all(&mut s.conn, Dir::Bi);
assert_eq!(claimed.len(), batch as usize);
let _ = drain(&mut s.conn);
let mut all = Vec::new();
for (_, r) in &claimed {
abandon_recv(&mut s.conn, t, *r);
let d = drain(&mut s.conn);
all.extend(s.drain_frames(&d));
}
assert!(
!all.iter().any(|f| matches!(f, Wire::MaxStreamsBidi(_))),
"§9.7: our send half is still live, so the stream is not fully \
closed and the peer has earned nothing — got {all:?}"
);
}
#[test]
fn an_abandoned_bidi_receive_half_discards_arrivals_without_reopening() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_bidi(0);
let _ = s.deliver(t, &stream_frame(id, 0, &ramp(0, 64), false));
let r = s.conn.accept(Dir::Bi).expect("open");
abandon_recv(&mut s.conn, t, r);
let _ = drain(&mut s.conn);
let d = s.deliver(t, &stream_frame(id, 64, &ramp(64, 64), false));
assert_alive(&d);
assert_eq!(
d.count_events(|e| matches!(e, ConnEvent::StreamOpened { .. })),
0,
"§16.2: arrivals for an abandoned half are discarded, never \
re-opened — a watermark-only build resurrects it here"
);
assert_eq!(
d.count_events(|e| matches!(e, ConnEvent::StreamReadable { .. })),
0,
"nothing was delivered, so nothing became readable"
);
}
#[test]
fn an_abandoned_bidi_receive_half_still_enforces_its_frozen_stream_limit() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_bidi(0);
let _ = s.deliver(t, &stream_frame(id, 0, &ramp(0, 64), false));
let r = s.conn.accept(Dir::Bi).expect("open");
abandon_recv(&mut s.conn, t, r);
let _ = drain(&mut s.conn);
let d = s.deliver(
t,
&stream_frame(id, INITIAL_MAX_STREAM_DATA, &[0u8; 1], false),
);
let frames = s.drain_frames(&d);
assert_violation(&d, &frames, FLOW_CONTROL_ERROR);
}
#[test]
fn abandoning_a_receive_half_releases_its_reassembly_capacity() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let _ = s.deliver_stream_bytes(t, id, 4096, 4096, false);
assert!(
s.conn.reassembly_capacity() > 0,
"an out-of-order range must be buffered somewhere"
);
let r = s.conn.accept(Dir::Uni).expect("open");
abandon_recv(&mut s.conn, t, r);
let _ = drain(&mut s.conn);
assert_eq!(
s.conn.reassembly_capacity(),
0,
"§9.7 frees the half; §10.6 makes that mean the memory too"
);
}
}
mod tombstone {
use super::*;
#[test]
fn a_duplicate_stream_frame_after_the_receive_half_is_freed_is_a_no_op() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let frame = stream_frame(id, 0, &ramp(0, 512), true);
let _ = s.deliver(t, &frame);
let r = s.conn.accept(Dir::Uni).expect("open");
let (got, eof) = read_available(&mut s.conn, t, r);
assert_eq!(got, ramp(0, 512));
assert!(eof, "§9.7: read to the final size frees the receive half");
let d = s.deliver(t, &frame);
assert_alive(&d);
assert_eq!(
d.count_events(|e| matches!(e, ConnEvent::StreamOpened { .. })),
0,
"§9.2: processed as acknowledged, never re-opened"
);
assert_eq!(
s.conn.accept(Dir::Uni),
None,
"no phantom stream is claimable"
);
assert_eq!(
s.conn.reassembly_capacity(),
0,
"and no reassembler was restarted"
);
}
#[test]
fn max_stream_data_for_a_stream_we_cannot_send_on_is_a_state_error() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let _ = s.deliver(t, &stream_frame(id, 0, &ramp(0, 16), false));
let d = s.deliver(t, &max_stream_data_frame(id, INITIAL_MAX_STREAM_DATA * 2));
let frames = s.drain_frames(&d);
assert_violation(&d, &frames, STREAM_STATE_ERROR);
}
#[test]
fn max_stream_data_for_an_unopened_stream_of_our_own_space_is_a_state_error() {
let t = t0();
let mut s = Solo::installed_at(t);
let ours = raw_id(0, Dir::Bi, false);
let d = s.deliver(t, &max_stream_data_frame(ours, INITIAL_MAX_STREAM_DATA * 2));
let frames = s.drain_frames(&d);
assert_violation(&d, &frames, STREAM_STATE_ERROR);
}
}
mod reassembly {
use super::*;
#[test]
fn ranges_arriving_out_of_order_reassemble_into_the_sent_bytes() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
for &(off, len) in &[(600u64, 200usize), (0, 200), (400, 200), (200, 200)] {
let last = off == 600;
let _ = s.deliver(t, &stream_frame(id, off, &ramp(off as usize, len), last));
}
let r = s.conn.accept(Dir::Uni).expect("open");
let (got, eof) = read_available(&mut s.conn, t, r);
assert_eq!(got.len(), 800, "every byte, once");
assert_eq!(got, ramp(0, 800), "and in offset order");
assert!(eof);
}
#[test]
fn overlapping_ranges_deliver_each_byte_exactly_once() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
for &(off, len, fin) in &[
(0u64, 300usize, false),
(200, 400, false),
(500, 300, false),
(0, 300, false),
(0, 800, true),
] {
let _ = s.deliver(t, &stream_frame(id, off, &ramp(off as usize, len), fin));
}
let r = s.conn.accept(Dir::Uni).expect("open");
let (got, eof) = read_available(&mut s.conn, t, r);
assert_eq!(got.len(), 800, "overlap adds no bytes");
assert_eq!(got, ramp(0, 800));
assert!(eof);
}
#[test]
fn a_hole_parks_the_reader_and_only_the_final_byte_ends_the_stream() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let mut buf = [0u8; 256];
let _ = s.deliver(t, &stream_frame(id, 0, &ramp(0, 100), false));
let _ = s.deliver(t, &stream_frame(id, 200, &ramp(200, 100), true));
let r = s.conn.accept(Dir::Uni).expect("open");
assert_eq!(
s.conn.read(t, r, &mut buf),
Ok(Some(100)),
"the contiguous prefix, and only it"
);
assert_eq!(
s.conn.read(t, r, &mut buf),
Ok(Some(0)),
"a hole is a park, not an end of stream — even though the FIN \
has already arrived"
);
let _ = s.deliver(t, &stream_frame(id, 100, &ramp(100, 100), false));
assert_eq!(
s.conn.read(t, r, &mut buf),
Ok(Some(200)),
"the gap and the tail"
);
assert_eq!(s.conn.read(t, r, &mut buf), Ok(None), "now the stream ends");
assert_eq!(s.conn.read(t, r, &mut buf), Ok(None), "and stays ended");
}
#[test]
fn a_fin_pins_the_final_size_at_the_frames_end_offset() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let d = s.deliver(t, &stream_frame(id, 0, &ramp(0, 500), true));
assert_alive(&d);
let d = s.deliver(t, &stream_frame(id, 500, &ramp(500, 4), false));
let frames = s.drain_frames(&d);
assert_violation(&d, &frames, FINAL_SIZE_ERROR);
}
#[test]
fn a_fin_at_the_high_water_offset_is_accepted_and_one_below_it_is_not() {
let t = t0();
let mut alive = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let _ = alive.deliver(t, &stream_frame(id, 0, &ramp(0, 400), false));
let d = alive.deliver(t, &stream_frame(id, 400, &[], true));
assert_alive(&d);
let r = alive.conn.accept(Dir::Uni).expect("open");
let (got, eof) = read_available(&mut alive.conn, t, r);
assert_eq!(got, ramp(0, 400));
assert!(
eof,
"a FIN at exactly the high-water offset ends the stream"
);
let mut dead = Solo::installed_at(t);
let _ = dead.deliver(t, &stream_frame(id, 0, &ramp(0, 400), false));
let d = dead.deliver(t, &stream_frame(id, 399, &[], true));
let frames = dead.drain_frames(&d);
assert_violation(&d, &frames, FINAL_SIZE_ERROR);
}
#[test]
fn two_fins_pinning_different_sizes_are_a_final_size_error() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let _ = s.deliver(t, &stream_frame(id, 0, &ramp(0, 100), true));
let d = s.deliver(t, &stream_frame(id, 0, &ramp(0, 100), true));
assert_alive(&d);
let d = s.deliver(t, &stream_frame(id, 0, &ramp(0, 90), true));
let frames = s.drain_frames(&d);
assert_violation(&d, &frames, FINAL_SIZE_ERROR);
}
#[test]
fn exactly_1024_stored_ranges_survive_and_the_1025th_is_a_protocol_violation() {
let t = t0();
let id = Solo::peer_uni(0);
let max = REASSEMBLY_CHUNKS_MAX as u64;
let one = |k: u64| stream_frame(id, 1 + 2 * k, &[(k % 251) as u8], false);
let mut alive = Solo::installed_at(t);
let frames: Vec<Vec<u8>> = (0..max).map(one).collect();
let d = alive.deliver_packed(t, &frames);
assert_alive(&d);
assert_eq!(
REASSEMBLY_CHUNKS_MAX, 1024,
"§10.6's ratified value; a change here needs a ruling"
);
let d = alive.deliver(t, &one(max));
let out = alive.drain_frames(&d);
assert_violation(&d, &out, PROTOCOL_VIOLATION);
}
#[test]
fn contiguous_ranges_coalesce_so_four_thousand_frames_survive() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
const N: usize = 4096;
const { assert!(N > REASSEMBLY_CHUNKS_MAX, "or this proves nothing") };
let payload = ramp(0, N);
let frames: Vec<Vec<u8>> = (0..N)
.rev()
.map(|i| stream_frame(id, i as u64, &payload[i..=i], false))
.collect();
let d = s.deliver_packed(t, &frames);
assert_alive(&d);
let d = s.deliver(t, &stream_frame(id, N as u64, &[], true));
assert_alive(&d);
let r = s.conn.accept(Dir::Uni).expect("open");
let (got, eof) = read_available(&mut s.conn, t, r);
assert_eq!(got, payload, "coalescing must not lose the gaps' contents");
assert!(eof);
}
#[test]
fn buffered_bytes_stay_within_the_connection_window_across_many_streams() {
let t = t0();
let mut s = Solo::installed_at(t);
let n = INITIAL_MAX_STREAMS_UNI;
let mut frames = vec![stream_frame(Solo::peer_uni(n - 1), 4, &[1u8], false)];
frames.extend((0..n).map(|i| stream_frame(Solo::peer_uni(i), 4, &[1u8], false)));
let d = s.deliver_packed(t, &frames);
assert_alive(&d);
assert_eq!(
d.count_events(|e| matches!(e, ConnEvent::StreamOpened { dir: Dir::Uni })),
n as usize,
"all 128 are open, so an eager allocator has allocated all 128"
);
let cap = s.conn.reassembly_capacity();
assert!(
cap <= INITIAL_MAX_DATA,
"§10.6: credit is the buffer commitment, and the connection \
window is 1 MiB — allocated {cap}"
);
assert!(
cap < n * INITIAL_MAX_STREAM_DATA,
"ruling 94: lazily, so nothing like the {} B an eager \
per-stream allocator would hold — allocated {cap}",
n * INITIAL_MAX_STREAM_DATA
);
}
#[test]
fn reassembly_capacity_returns_to_zero_when_the_half_is_read_out() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
assert_eq!(s.conn.reassembly_capacity(), 0, "nothing yet");
let _ = s.deliver_stream_bytes(t, id, 2048, 2048, false);
assert!(
s.conn.reassembly_capacity() > 0,
"an out-of-order range has to live somewhere"
);
let _ = s.deliver_stream_bytes(t, id, 0, 2048, false);
let _ = s.deliver(t, &stream_frame(id, 4096, &[], true));
let r = s.conn.accept(Dir::Uni).expect("open");
let (got, eof) = read_available(&mut s.conn, t, r);
assert_eq!(got, ramp(0, 4096));
assert!(eof);
assert_eq!(
s.conn.reassembly_capacity(),
0,
"§9.7 frees at read-to-final, and §10.6 makes that mean the \
memory too"
);
}
}
mod flow_control {
use super::*;
fn credit_frames(s: &mut Solo, d: &Drained) -> Vec<Wire> {
s.drain_frames(d)
.into_iter()
.filter(|f| {
matches!(
f,
Wire::MaxData(_)
| Wire::MaxStreamData { .. }
| Wire::MaxStreamsBidi(_)
| Wire::MaxStreamsUni(_)
)
})
.collect()
}
#[test]
fn one_byte_read_emits_no_credit_at_all() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let _ = s.deliver(t, &stream_frame(id, 0, &[7u8], false));
let r = s.conn.accept(Dir::Uni).expect("open");
assert_eq!(s.conn.read(t, r, &mut [0u8; 8]), Ok(Some(1)));
tick(&mut s.conn, t);
let d = drain(&mut s.conn);
assert_eq!(
credit_frames(&mut s, &d),
Vec::new(),
"§10.3: the seed is the constant, so one byte is nowhere near \
WINDOW/2 and nothing is owed"
);
}
#[test]
fn a_max_stream_data_arrives_at_exactly_half_a_window_read_and_not_before() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let half = INITIAL_MAX_STREAM_DATA / 2;
let _ = s.deliver_stream_bytes(t, id, 0, half as usize + 16, false);
let r = s.conn.accept(Dir::Uni).expect("open");
let _ = read_exactly(&mut s.conn, t, r, half as usize - 1);
tick(&mut s.conn, t);
let d = drain(&mut s.conn);
assert_eq!(
credit_frames(&mut s, &d),
Vec::new(),
"one byte short of WINDOW/2 owes nothing"
);
let _ = read_exactly(&mut s.conn, t, r, 1);
tick(&mut s.conn, t);
let d = drain(&mut s.conn);
assert_eq!(
credit_frames(&mut s, &d),
vec![Wire::MaxStreamData {
id,
max: half + INITIAL_MAX_STREAM_DATA
}],
"§10.3: absolute — `bytes_read + WINDOW`, exactly once"
);
}
#[test]
fn max_data_arrives_at_half_the_connection_window_consumed() {
let t = t0();
let mut s = Solo::installed_at(t);
let half_conn = INITIAL_MAX_DATA / 2;
let per = (half_conn / 4) as usize;
let ids: Vec<u64> = (0..4).map(Solo::peer_uni).collect();
let _ = s.deliver(t, &stream_frame(ids[3], 0, &[], false));
let claimed = accept_all(&mut s.conn, Dir::Uni);
assert_eq!(claimed.len(), 4);
for id in &ids {
let _ = s.deliver_stream_bytes(t, *id, 0, per, false);
}
let _ = drain(&mut s.conn);
for (_, r) in claimed.iter().take(3) {
let _ = read_exactly(&mut s.conn, t, *r, per);
}
tick(&mut s.conn, t);
let d = drain(&mut s.conn);
let seen = credit_frames(&mut s, &d);
assert!(
!seen.iter().any(|f| matches!(f, Wire::MaxData(_))),
"3/8 of the connection window is below the 1/2 trigger, though \
every one of those streams crossed its own — {seen:?}"
);
let _ = read_exactly(&mut s.conn, t, claimed[3].1, per);
tick(&mut s.conn, t);
let d = drain(&mut s.conn);
let seen = credit_frames(&mut s, &d);
assert!(
seen.contains(&Wire::MaxData(half_conn + INITIAL_MAX_DATA)),
"§10.3 at the connection level, absolute — {seen:?}"
);
}
#[test]
fn stream_data_ending_exactly_at_the_window_is_legal_and_one_byte_past_kills() {
let t = t0();
let id = Solo::peer_uni(0);
let mut alive = Solo::installed_at(t);
let d = alive.deliver(
t,
&stream_frame(id, INITIAL_MAX_STREAM_DATA - 1, &[9u8], false),
);
assert_alive(&d);
let mut dead = Solo::installed_at(t);
let d = dead.deliver(t, &stream_frame(id, INITIAL_MAX_STREAM_DATA, &[9u8], false));
let frames = dead.drain_frames(&d);
assert_violation(&d, &frames, FLOW_CONTROL_ERROR);
}
#[test]
fn the_sum_of_stream_offsets_is_bounded_by_the_connection_window() {
let t = t0();
let per = INITIAL_MAX_STREAM_DATA;
let n = INITIAL_MAX_DATA / per;
let fill = |s: &mut Solo| {
let _ = s.deliver(t, &stream_frame(Solo::peer_uni(n), 0, &[], false));
for i in 0..n {
let _ = s.deliver(t, &stream_frame(Solo::peer_uni(i), per - 1, &[3u8], false));
}
};
let mut alive = Solo::installed_at(t);
fill(&mut alive);
let d = drain(&mut alive.conn);
assert_alive(&d);
let mut dead = Solo::installed_at(t);
fill(&mut dead);
let d = dead.deliver(t, &stream_frame(Solo::peer_uni(n), 0, &[3u8], false));
let frames = dead.drain_frames(&d);
assert_violation(&d, &frames, FLOW_CONTROL_ERROR);
}
#[test]
fn a_fresh_stream_blocks_at_once_when_the_connection_window_is_spent() {
let t = t0();
let mut p = Pair::installed_at(t);
let n = (INITIAL_MAX_DATA / INITIAL_MAX_STREAM_DATA) as usize;
for _ in 0..n {
let r = p.a.open(Dir::Uni).expect("open");
assert_eq!(
write_until_blocked(&mut p.a, t, r),
INITIAL_MAX_STREAM_DATA,
"each stream takes exactly its own window"
);
}
let fresh = p.a.open(Dir::Uni).expect("open");
assert_eq!(
write_until_blocked(&mut p.a, t, fresh),
0,
"§10.1: whichever limit is tighter binds, and the connection \
window is spent — a fresh stream window buys nothing"
);
}
#[test]
fn open_succeeds_thirty_two_times_and_the_thirty_third_is_exhausted() {
let t = t0();
let mut p = Pair::installed_at(t);
for i in 0..INITIAL_MAX_STREAMS_BIDI {
let r =
p.a.open(Dir::Bi)
.unwrap_or_else(|_| panic!("index {i} is inside the limit"));
assert_eq!(p.a.stream_id(r).expect("established").index(), i);
}
assert!(
p.a.open(Dir::Bi).is_err(),
"§10.4: the limit counts streams ever opened"
);
assert!(
p.a.open(Dir::Uni).is_ok(),
"the uni space has its own, untouched allowance"
);
}
#[test]
fn max_streams_is_cumulative_and_wakes_a_blocked_opener() {
let t = t0();
let mut s = Solo::installed_at(t);
for _ in 0..INITIAL_MAX_STREAMS_UNI {
s.conn.open(Dir::Uni).expect("inside the initial allowance");
}
assert!(s.conn.open(Dir::Uni).is_err(), "exhausted");
let d = s.deliver(t, &max_streams_uni_frame(INITIAL_MAX_STREAMS_UNI + 1));
assert_alive(&d);
assert_eq!(
d.count_events(|e| matches!(e, ConnEvent::StreamsAvailable { dir: Dir::Uni })),
1,
"§10.4: receipt surfaces StreamsAvailable to wake blocked openers"
);
assert!(s.conn.open(Dir::Uni).is_ok(), "the one stream 129 buys");
assert!(
s.conn.open(Dir::Uni).is_err(),
"and only one: the count is cumulative, not incremental"
);
}
#[test]
fn a_lower_credit_grant_is_a_no_op_not_a_reduction() {
let t = t0();
let mut s = Solo::installed_at(t);
let r = s.conn.open(Dir::Uni).expect("open");
let id = s.conn.stream_id(r).expect("established").as_u64();
let raised = INITIAL_MAX_STREAM_DATA * 2;
let _ = s.deliver(t, &max_stream_data_frame(id, raised));
let _ = s.deliver(t, &max_stream_data_frame(id, INITIAL_MAX_STREAM_DATA / 2));
let d = s.deliver(t, &max_data_frame(1));
assert_alive(&d);
assert_eq!(
write_until_blocked(&mut s.conn, t, r),
raised,
"§8.4: monotone-max — the stale, lower grants changed nothing"
);
}
#[test]
fn max_stream_data_raises_the_limit_and_wakes_the_blocked_writer() {
let t = t0();
let mut s = Solo::installed_at(t);
let r = s.conn.open(Dir::Uni).expect("open");
let id = s.conn.stream_id(r).expect("established").as_u64();
assert_eq!(
write_until_blocked(&mut s.conn, t, r),
INITIAL_MAX_STREAM_DATA
);
let _ = drain(&mut s.conn);
let d = s.deliver(
t,
&max_stream_data_frame(id, INITIAL_MAX_STREAM_DATA + 4096),
);
assert_eq!(
d.count_events(|e| matches!(e, ConnEvent::StreamWritable { r: got } if *got == r)),
1,
"§16.4: credit arrived for a blocked writer"
);
assert_eq!(
write_until_blocked(&mut s.conn, t, r),
4096,
"and the ledger actually moved, by exactly the grant"
);
}
#[test]
fn a_max_streams_of_two_to_the_sixty_is_legal_and_one_more_is_structural() {
let t = t0();
let ceiling = 1u64 << 60;
let mut alive = Solo::installed_at(t);
let d = alive.deliver(t, &max_streams_bidi_frame(ceiling));
assert_alive(&d);
let mut dead = Solo::installed_at(t);
let d = dead.deliver(t, &max_streams_bidi_frame(ceiling + 1));
let frames = dead.drain_frames(&d);
assert_violation(&d, &frames, PROTOCOL_VIOLATION);
}
}
mod reset {
use super::*;
const APP_CODE: u64 = 0x2a;
#[test]
fn a_reset_stream_surfaces_read_error_reset_with_the_peers_code() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let _ = s.deliver(t, &stream_frame(id, 0, &ramp(0, 64), false));
let r = s.conn.accept(Dir::Uni).expect("open");
let d = s.deliver(t, &reset_frame(id, APP_CODE, 64));
assert_alive(&d);
assert_eq!(
d.count_events(
|e| matches!(e, ConnEvent::StreamReset { r: got, error_code }
if *got == r && *error_code == APP_CODE)
),
1,
"§16.4: the reset is signalled, with the peer's code"
);
assert_eq!(
s.conn.read(t, r, &mut [0u8; 64]),
Err(ReadError::Reset(APP_CODE)),
"§9.6: the receive half surfaces the reset, not the buffered bytes"
);
}
#[test]
fn a_reset_stream_discards_the_reassembly_buffer() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let _ = s.deliver_stream_bytes(t, id, 8192, 8192, false);
assert!(s.conn.reassembly_capacity() > 0);
let _ = s.deliver(t, &reset_frame(id, APP_CODE, 16384));
assert_eq!(
s.conn.reassembly_capacity(),
0,
"§9.6: the buffer goes with the stream's data"
);
}
#[test]
fn a_reset_final_size_at_the_window_is_legal_and_one_past_is_a_flow_control_error() {
let t = t0();
let id = Solo::peer_uni(0);
let mut alive = Solo::installed_at(t);
let _ = alive.deliver(t, &stream_frame(id, 0, &[1u8], false));
let d = alive.deliver(t, &reset_frame(id, 7, INITIAL_MAX_STREAM_DATA));
assert_alive(&d);
let mut dead = Solo::installed_at(t);
let _ = dead.deliver(t, &stream_frame(id, 0, &[1u8], false));
let d = dead.deliver(t, &reset_frame(id, APP_CODE, INITIAL_MAX_STREAM_DATA + 1));
let frames = dead.drain_frames(&d);
assert_violation(&d, &frames, FLOW_CONTROL_ERROR);
}
#[test]
fn a_reset_final_size_at_the_varint_ceiling_is_rejected_without_wrapping() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let _ = s.deliver(t, &stream_frame(id, 0, &ramp(0, 128), false));
let _ = drain(&mut s.conn);
let d = s.deliver(t, &reset_frame(id, APP_CODE, VarInt::MAX_VALUE));
let frames = s.drain_frames(&d);
assert_violation(&d, &frames, FLOW_CONTROL_ERROR);
assert!(
!frames
.iter()
.any(|f| matches!(f, Wire::MaxData(_) | Wire::MaxStreamData { .. })),
"a wrapped or saturating-then-advanced ledger emits a grant \
here — {frames:?}"
);
}
#[test]
fn a_reset_agreeing_with_a_pinned_final_size_is_a_no_op_and_disagreeing_kills() {
let t = t0();
let id = Solo::peer_uni(0);
let mut alive = Solo::installed_at(t);
let _ = alive.deliver(t, &stream_frame(id, 0, &ramp(0, 200), true));
let d = alive.deliver(t, &reset_frame(id, APP_CODE, 200));
assert_alive(&d);
let mut dead = Solo::installed_at(t);
let _ = dead.deliver(t, &stream_frame(id, 0, &ramp(0, 200), true));
let d = dead.deliver(t, &reset_frame(id, APP_CODE, 201));
let frames = dead.drain_frames(&d);
assert_violation(&d, &frames, FINAL_SIZE_ERROR);
}
#[test]
fn a_reset_final_size_below_the_highest_received_offset_is_a_final_size_error() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let _ = s.deliver(t, &stream_frame(id, 400, &ramp(400, 100), false));
let d = s.deliver(t, &reset_frame(id, APP_CODE, 499));
let frames = s.drain_frames(&d);
assert_violation(&d, &frames, FINAL_SIZE_ERROR);
}
#[test]
fn a_reset_stream_on_a_space_the_peer_cannot_send_on_is_a_state_error() {
let t = t0();
let mut s = Solo::installed_at(t);
let d = s.deliver(t, &reset_frame(Solo::our_uni(0), APP_CODE, 0));
let frames = s.drain_frames(&d);
assert_violation(&d, &frames, STREAM_STATE_ERROR);
}
#[test]
fn our_reset_carries_the_highest_byte_sent_as_its_final_size() {
let t = t0();
let mut s = Solo::installed_at(t);
let written = s.conn.open(Dir::Uni).expect("open");
let written_id = s.conn.stream_id(written).expect("established").as_u64();
let payload = ramp(0, 5000);
assert_eq!(write_all(&mut s.conn, t, written, &payload), 0);
let _ = drain(&mut s.conn);
s.conn.reset(t, written, APP_CODE);
let d = drain(&mut s.conn);
let frames = s.drain_frames(&d);
assert!(
frames.contains(&Wire::Reset {
id: written_id,
code: APP_CODE,
final_size: 5000
}),
"§9.6: the end offset of the highest byte sent — {frames:?}"
);
let empty = s.conn.open(Dir::Uni).expect("open");
let empty_id = s.conn.stream_id(empty).expect("established").as_u64();
s.conn.reset(t, empty, APP_CODE);
let d = drain(&mut s.conn);
let frames = s.drain_frames(&d);
assert!(
frames.contains(&Wire::Reset {
id: empty_id,
code: APP_CODE,
final_size: 0
}),
"§9.6: 0 if none — {frames:?}"
);
}
#[test]
fn write_after_reset_is_a_write_error() {
let t = t0();
let mut s = Solo::installed_at(t);
let r = s.conn.open(Dir::Uni).expect("open");
assert_eq!(write_all(&mut s.conn, t, r, &ramp(0, 100)), 0);
s.conn.reset(t, r, APP_CODE);
assert_eq!(
s.conn.write(t, r, &[1u8; 4]),
Err(WriteError::Finished),
"§9.3: `ResetSent` has no incoming write edge"
);
}
#[test]
fn observing_a_reset_brings_the_streams_contribution_to_its_final_size() {
let t = t0();
let mut s = Solo::installed_at(t);
let per = INITIAL_MAX_DATA / 4;
let ids = [Solo::peer_uni(0), Solo::peer_uni(1)];
let _ = s.deliver(t, &stream_frame(ids[1], 0, &[], false));
let claimed = accept_all(&mut s.conn, Dir::Uni);
assert_eq!(claimed.len(), 2);
for (i, id) in ids.iter().enumerate() {
let _ = s.deliver(t, &stream_frame(*id, 0, &ramp(0, 128), false));
let _ = read_exactly(&mut s.conn, t, claimed[i].1, 128);
}
let _ = drain(&mut s.conn);
let _ = s.deliver(t, &reset_frame(ids[0], APP_CODE, per));
assert_eq!(
s.conn.read(t, claimed[0].1, &mut [0u8; 8]),
Err(ReadError::Reset(APP_CODE))
);
tick(&mut s.conn, t);
let d = drain(&mut s.conn);
let f = s.drain_frames(&d);
assert!(
!f.iter().any(|w| matches!(w, Wire::MaxData(_))),
"one retired stream is half the trigger — {f:?}"
);
let _ = s.deliver(t, &reset_frame(ids[1], APP_CODE, per));
assert_eq!(
s.conn.read(t, claimed[1].1, &mut [0u8; 8]),
Err(ReadError::Reset(APP_CODE))
);
tick(&mut s.conn, t);
let d = drain(&mut s.conn);
let f = s.drain_frames(&d);
assert!(
f.contains(&Wire::MaxData(2 * per + INITIAL_MAX_DATA)),
"§10.3: absolute — `2 × final_size`, with the 256 bytes already \
read folded in, not added on top — {f:?}"
);
}
}
mod sealing {
use super::*;
fn last_send(s: &Solo) -> Instant {
s.conn.liveness().expect("established").last_send()
}
fn eight_uni_closures(t: Instant) -> Solo {
let mut s = Solo::installed_at(t);
let batch = STREAMS_CREDIT_BATCH;
for i in 0..batch {
let _ = s.deliver(t, &stream_frame(Solo::peer_uni(i), 0, &ramp(0, 16), true));
}
let claimed = accept_all(&mut s.conn, Dir::Uni);
assert_eq!(claimed.len(), batch as usize);
for (_, r) in &claimed {
let (got, eof) = read_available(&mut s.conn, t, *r);
assert_eq!(got.len(), 16);
assert!(eof, "§9.7: read to the final size frees the half");
}
s
}
#[test]
fn a_max_streams_only_packet_does_not_defer_the_keepalive() {
let t = t0();
let t1 = t + Duration::from_secs(1);
let mut s = eight_uni_closures(t);
let before = last_send(&s);
s.conn.handle_timeout(t1);
let d = drain(&mut s.conn);
let packets = s.packets(&d);
let all: Vec<Wire> = packets.iter().flatten().cloned().collect();
assert_eq!(
all.iter()
.filter(|f| !matches!(f, Wire::Padding | Wire::Ack { .. }))
.cloned()
.collect::<Vec<_>>(),
vec![Wire::MaxStreamsUni(
INITIAL_MAX_STREAMS_UNI + STREAMS_CREDIT_BATCH
)],
"the fixture must produce a credit-bearing packet or this test \
asserts nothing — {all:?}"
);
assert_eq!(
last_send(&s),
before,
"§7.4: the credit frames are the quiet set — `seal_quiet` \
leaves `last_send` untouched"
);
assert!(
s.conn.liveness().expect("established").is_armed(),
"§7.4: and, being ack-eliciting, it arms the death clock"
);
assert!(
d.deadline.is_some(),
"§16.4: the drain ends on that armed deadline, not `Timeout(None)`"
);
}
#[test]
fn a_first_transmission_stream_frame_marks_last_send() {
let t = t0();
let t1 = t + Duration::from_secs(1);
let mut s = Solo::installed_at(t);
let before = last_send(&s);
let r = s.conn.open(Dir::Uni).expect("open");
assert_eq!(write_all(&mut s.conn, t1, r, &ramp(0, 4096)), 0);
let d = drain(&mut s.conn);
assert!(
!d.transmits().is_empty(),
"the write must have reached the wire"
);
assert_eq!(
last_send(&s),
t1,
"§7.4: a fresh application send is marking — `seal`"
);
assert_ne!(before, t1, "the fixture must actually move the clock");
}
#[test]
fn a_reset_stream_only_packet_does_not_mark_last_send() {
let t = t0();
let t1 = t + Duration::from_secs(1);
let mut s = Solo::installed_at(t);
let r = s.conn.open(Dir::Uni).expect("open");
let _ = drain(&mut s.conn);
let before = last_send(&s);
s.conn.reset(t1, r, 0x2a);
let d = drain(&mut s.conn);
let frames = s.drain_frames(&d);
assert!(
frames.iter().any(|f| matches!(f, Wire::Reset { .. })),
"the reset must have reached the wire — {frames:?}"
);
assert!(
!frames.iter().any(|f| matches!(f, Wire::Stream { .. })),
"nothing was written, so no STREAM frame can mark this packet"
);
assert_eq!(
last_send(&s),
before,
"ruling 98: RESET_STREAM is in §7.4's quiet set"
);
}
}
mod packing {
use super::*;
#[test]
fn at_most_one_extends_to_end_frame_per_packet_and_it_is_last() {
let t = t0();
let mut s = Solo::installed_at(t);
let a = s.conn.open(Dir::Uni).expect("open");
let b = s.conn.open(Dir::Uni).expect("open");
assert_eq!(write_all(&mut s.conn, t, a, &ramp(0, 32 * 1024)), 0);
assert_eq!(write_all(&mut s.conn, t, b, &ramp(0, 32 * 1024)), 0);
let d = drain(&mut s.conn);
let packets = s.packets(&d);
assert!(packets.len() > 8, "64 KiB must span many packets");
for pkt in &packets {
let open_ended: Vec<usize> = pkt
.iter()
.enumerate()
.filter(|(_, f)| matches!(f, Wire::Stream { had_len: false, .. }))
.map(|(i, _)| i)
.collect();
assert!(
open_ended.len() <= 1,
"§8.5: at most one extends-to-end frame — {pkt:?}"
);
if let Some(&i) = open_ended.first() {
assert_eq!(
i,
pkt.len() - 1,
"§8.5: and it is the packet's final frame — {pkt:?}"
);
}
}
}
#[test]
fn the_stream_fill_serves_pending_streams_round_robin() {
let t = t0();
let (mut conn, sa, sb) = Solo::connecting();
let a = conn.open(Dir::Uni).expect("open");
let b = conn.open(Dir::Uni).expect("open");
assert!(
conn.stream_id(a).is_none(),
"§16.9: no wire id before the install — if this is Some, the fixture is not testing what it claims to"
);
assert_eq!(write_all(&mut conn, t, a, &ramp(0, 32 * 1024)), 0);
assert_eq!(write_all(&mut conn, t, b, &ramp(0, 32 * 1024)), 0);
assert!(
drain(&mut conn).transmits().is_empty(),
"nothing can be on the wire before the install"
);
conn.handle_endpoint_event(
t,
Install {
session: sb,
role: Role::Responder,
anchor_from_msg1: false,
},
);
let d = drain(&mut conn);
let mut s = Solo::around(conn, sa);
let a_id = s.conn.stream_id(a).expect("established").as_u64();
let b_id = s.conn.stream_id(b).expect("established").as_u64();
let order: Vec<u64> = s
.drain_frames(&d)
.iter()
.filter_map(|f| match f {
Wire::Stream { id, .. } => Some(*id),
_ => None,
})
.collect();
let first = |want: u64| order.iter().position(|id| *id == want);
let last = |want: u64| order.iter().rposition(|id| *id == want);
assert!(first(a_id).is_some() && first(b_id).is_some(), "{order:?}");
assert!(
first(b_id) < last(a_id),
"§8.5: B started before A finished — a sequential fill cannot \
do this: {order:?}"
);
assert!(first(a_id) < last(b_id), "and symmetrically: {order:?}");
}
#[test]
fn credit_frames_precede_the_stream_fill_in_a_packet() {
let t = t0();
let mut s = Solo::installed_at(t);
let mine = s.conn.open(Dir::Uni).expect("open");
assert_eq!(write_all(&mut s.conn, t, mine, &ramp(0, 32 * 1024)), 0);
let burst = drain(&mut s.conn);
let highest = s.conn.next_counter().expect("established") - 1;
assert!(
!burst.transmits().is_empty(),
"the first flight must leave, or the window was never filled"
);
let id = Solo::peer_uni(0);
let half = (INITIAL_MAX_STREAM_DATA / 2) as usize;
let _ = s.deliver_stream_bytes(t, id, 0, half, false);
let r = s.conn.accept(Dir::Uni).expect("open");
let _ = read_exactly(&mut s.conn, t, r, half);
let mut ack = Vec::new();
put(&mut ack, crate::constants::FRAME_ACK);
put(&mut ack, highest); put(&mut ack, 0); put(&mut ack, 0); put(&mut ack, highest); let d = s.deliver_packed(t, &[ack]);
let packets = s.packets(&d);
let mut found = false;
for pkt in &packets {
let credit = pkt
.iter()
.position(|f| matches!(f, Wire::MaxStreamData { .. } | Wire::MaxData(_)));
let stream = pkt.iter().position(|f| matches!(f, Wire::Stream { .. }));
if let (Some(c), Some(st)) = (credit, stream) {
found = true;
assert!(c < st, "§8.5: control frames, then the fill — {pkt:?}");
}
}
assert!(
found,
"no packet carried both a credit frame and stream data, so this \
test asserted nothing: {packets:?}"
);
}
fn stream_shape(pkt: &[Wire]) -> Vec<(u64, u64, usize, bool)> {
pkt.iter()
.filter_map(|f| match f {
Wire::Stream {
id,
offset,
data,
fin,
..
} => Some((*id, *offset, data.len(), *fin)),
_ => None,
})
.collect()
}
#[test]
fn a_bare_fin_against_a_full_packet_defers_to_the_next_packet() {
let t = t0();
let mut s = Solo::installed_at(t);
let r = s.conn.open(Dir::Uni).expect("open");
let id = s.conn.stream_id(r).expect("installed").as_u64();
assert_eq!(write_all(&mut s.conn, t, r, &ramp(0, 2048)), 0);
s.conn.finish(t, r).expect("finish");
let filler = s.conn.open(Dir::Uni).expect("open");
assert_eq!(write_all(&mut s.conn, t, filler, &ramp(0, 4096)), 0);
let first = drain(&mut s.conn);
let sent = s.packets(&first);
assert_eq!(
stream_shape(&sent[0]),
vec![(id, 0, 1024, false), (id, 1024, 136, false)],
"the premise: one quantum plus what the length varints leave is \
`MAX_PLAINTEXT` to the byte"
);
assert_eq!(
first.transmits()[0].data.len(),
MAX_DATAGRAM,
"§8.6: a plaintext of `MAX_PLAINTEXT` is a datagram of \
`MAX_DATAGRAM`; if this packet is not full the rest of this \
test asserts nothing"
);
assert_eq!(
stream_shape(&sent[2]),
vec![(id, 2048, 0, true)],
"§9.5's empty end-of-stream marker, alone in its packet — the \
bare obligation this test is about"
);
let highest = s.conn.next_counter().expect("established") - 1;
assert!(
highest >= 5,
"counter 2 is only reachable by the packet threshold once the \
largest acknowledged is 5 or more; got {highest}"
);
let mut ack = Vec::new();
put(&mut ack, crate::constants::FRAME_ACK);
put(&mut ack, highest); put(&mut ack, 0); put(&mut ack, 1); put(&mut ack, highest - 3); put(&mut ack, 0); put(&mut ack, 0); let d = s.deliver_packed(t, &[ack]);
let rtx = s.packets(&d);
assert_eq!(
stream_shape(&rtx[0]),
vec![(id, 0, 1024, false), (id, 1024, 136, false)],
"§8.7: only the still-unacknowledged prefix is resent, and it \
fills the packet exactly"
);
assert_eq!(
d.transmits()[0].data.len(),
MAX_DATAGRAM,
"the retransmission packet is full to the byte — the state in \
which `stream_payload_room` answers `None` and a bare FIN has \
nowhere to go"
);
assert_eq!(
rtx.len(),
2,
"ruling 257: the refused FIN is **deferred**, not dropped — a \
build that strands it sends the retransmission alone"
);
assert_eq!(
stream_shape(&rtx[1]),
vec![(id, 2048, 0, true)],
"ruling 257: the deferred FIN is emitted by the **very next** \
packet. A build that defers by leaving the rotation, or that \
loses `return_chunk`'s `fin_sent = false`, strands it here"
);
let highest = s.conn.next_counter().expect("established") - 1;
let mut ack_all = Vec::new();
put(&mut ack_all, crate::constants::FRAME_ACK);
put(&mut ack_all, highest);
put(&mut ack_all, 0);
put(&mut ack_all, 0);
put(&mut ack_all, highest);
let done = s.deliver_packed(t, &[ack_all]);
assert_eq!(
done.count_events(|e| matches!(e, ConnEvent::StreamFinished { r: got } if *got == r)),
1,
"§9.7: every byte and the FIN are acknowledged, so the send half \
is `DataRecvd`"
);
}
}
mod slice_boundary {
use super::*;
#[test]
fn a_send_half_reports_finished_once_the_peer_acknowledges() {
let t = t0();
let mut p = Pair::installed_at(t);
let r = p.a.open(Dir::Uni).expect("open");
assert_eq!(write_all(&mut p.a, t, r, &ramp(0, 8192)), 0);
p.a.finish(t, r).expect("finish");
let (da, db) = p.pump(t);
let rb = p.b.accept(Dir::Uni).expect("the peer saw the stream");
let (got, eof) = read_available(&mut p.b, t, rb);
assert_eq!(got, ramp(0, 8192));
assert!(eof);
assert_eq!(
da.count_events(|e| matches!(e, ConnEvent::StreamFinished { .. })),
1,
"§9.3 with §12: every byte and the FIN acknowledged, so the send \
half reaches `DataRecvd` exactly once"
);
assert_eq!(
db.count_events(|e| matches!(e, ConnEvent::StreamFinished { .. })),
0,
"and the receiving side has no send half to finish at all"
);
}
#[test]
fn a_transmit_and_the_event_it_caused_leave_in_generation_order() {
let t = t0();
let mut s = Solo::installed_at(t);
let d = s.deliver(t, &stream_frame(Solo::our_uni(0), 0, &ramp(0, 4), false));
let close_at = d
.position(|o| matches!(o, ConnOutput::Transmit(_)))
.expect("§8.2 sends a CLOSE");
let closed_at = d
.position(|o| matches!(o, ConnOutput::Event(ConnEvent::Closed(_))))
.expect("§8.2 surfaces the loss");
assert!(
close_at < closed_at,
"§16.4: generation order — {:?}",
d.outs
);
}
#[test]
fn the_reserved_stop_sending_type_is_still_a_structural_error() {
let t = t0();
let mut s = Solo::installed_at(t);
let mut f = Vec::new();
put(&mut f, crate::constants::FRAME_STOP_SENDING_RESERVED);
put(&mut f, Solo::peer_uni(0));
put(&mut f, 0);
let d = s.deliver(t, &f);
let frames = s.drain_frames(&d);
assert_violation(&d, &frames, PROTOCOL_VIOLATION);
}
}
mod offset_ceiling {
use super::*;
#[test]
fn a_stream_frame_ending_exactly_at_the_varint_ceiling_clears_the_structural_guard() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let offset = VarInt::MAX_VALUE - 1;
assert_eq!(
offset + 1,
VarInt::MAX_VALUE,
"precondition: this frame ends *at* §8.4's ceiling, not below it",
);
assert!(
offset > INITIAL_MAX_STREAM_DATA,
"precondition: it is also far outside §10's window, so \
FLOW_CONTROL_ERROR is the disposition a decoder that passed it \
must produce",
);
let d = s.deliver(t, &stream_frame(id, offset, &[0xab], false));
let frames = s.drain_frames(&d);
assert_violation(&d, &frames, FLOW_CONTROL_ERROR);
}
#[test]
fn a_stream_frame_ending_one_byte_past_the_varint_ceiling_is_a_structural_error() {
let t = t0();
let mut s = Solo::installed_at(t);
let id = Solo::peer_uni(0);
let d = s.deliver(t, &stream_frame(id, VarInt::MAX_VALUE, &[0xab], false));
let frames = s.drain_frames(&d);
assert_violation(&d, &frames, PROTOCOL_VIOLATION);
}
}