use bytes::Bytes;
use velo_ext::WorkerId;
use super::*;
use crate::streaming::messenger_mux::protocol::{BatchEncoder, RecordType, SlotId};
use crate::streaming::sender::{cached_dropped, cached_finalized};
const PEER: u64 = 0xABCD;
const ANCHOR: u64 = 7;
const SESSION: u64 = 11;
fn peer() -> WorkerId {
WorkerId::from_u64(PEER)
}
fn config() -> MuxConfig {
MuxConfig {
initial_credit: 4,
slot_byte_budget: 256,
peer_byte_budget: 4096,
..MuxConfig::default()
}
}
fn slot(index: u32, generation: u8) -> SlotId {
SlotId::new(index, generation).expect("index fits u24")
}
fn batch(epoch: u64, batch_seq: u32, build: impl FnOnce(&mut BatchEncoder)) -> Bytes {
let mut encoder = BatchEncoder::new(epoch, batch_seq);
build(&mut encoder);
encoder.finish().freeze()
}
fn item(n: u8) -> Vec<u8> {
rmp_serde::to_vec(&crate::streaming::frame::StreamFrame::Item(n)).expect("encode item")
}
fn bound() -> (IngressRegistry, flume::Receiver<Vec<u8>>, MuxConfig) {
let config = config();
let registry = IngressRegistry::default();
let (tx, rx) = flume::bounded(
crate::streaming::messenger_mux::flow_control::slot_buffer_depth(config.initial_credit),
);
registry.register_bind(ANCHOR, SESSION, tx);
(registry, rx, config)
}
fn open(registry: &IngressRegistry, config: &MuxConfig, id: SlotId, epoch: u64) -> BatchOutcome {
let payload = batch(epoch, 0, |encoder| {
encoder.push_open_slot(id, 0, ANCHOR, SESSION).unwrap();
});
handle_batch(registry, config, None, peer(), &payload)
}
fn drain(rx: &flume::Receiver<Vec<u8>>) -> Vec<Vec<u8>> {
let mut out = Vec::new();
while let Ok(frame) = rx.try_recv() {
out.push(frame);
}
out
}
#[test]
fn open_slot_claims_the_matching_bind_and_grants_no_credit() {
let (registry, _rx, config) = bound();
let id = slot(0, 0);
let outcome = open(®istry, &config, id, 1);
assert_eq!(outcome.opened, 1);
assert_eq!(registry.live_slots(peer()), 1);
assert!(
outcome.replies.is_empty(),
"the window was advertised on the attach response and the sender \
opened already holding it; granting it again here would hand the \
sender 2C against a C + 1 buffer, which is the reader stall the \
credit invariant exists to make impossible"
);
}
#[test]
fn open_slot_for_an_unregistered_anchor_rejects_that_slot_only() {
let (registry, _rx, config) = bound();
let id = slot(3, 0);
let payload = batch(1, 0, |encoder| {
encoder.push_open_slot(id, 0, 999, 999).unwrap();
});
let outcome = handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(outcome.opened, 0);
assert_eq!(
outcome.replies,
vec![ReplyRecord::CloseSlot {
slot: id,
reason: CloseReason::UnknownSlot
}],
"the reverse race must not fail the peer"
);
let outcome = open(®istry, &config, slot(0, 0), 1);
assert_eq!(outcome.opened, 1);
}
#[test]
fn a_colliding_open_slot_is_rejected_and_the_incumbent_survives() {
let config = config();
let registry = IngressRegistry::default();
let depth =
crate::streaming::messenger_mux::flow_control::slot_buffer_depth(config.initial_credit);
let (incumbent_tx, incumbent_rx) = flume::bounded(depth);
registry.register_bind(ANCHOR, SESSION, incumbent_tx);
let (rival_tx, rival_rx) = flume::bounded(depth);
registry.register_bind(ANCHOR, SESSION + 1, rival_tx);
let incumbent = slot(0, 0);
open(®istry, &config, incumbent, 1);
let payload = batch(1, 1, |encoder| {
encoder.push_data(incumbent, 2, &item(2)).unwrap();
});
handle_batch(®istry, &config, None, peer(), &payload);
let held_bytes = registry.peer_bytes_used(peer());
assert!(
held_bytes > 0,
"the hold has to be charged for this to test anything"
);
let collider = slot(0, 1);
let payload = batch(1, 2, |encoder| {
encoder
.push_open_slot(collider, 0, ANCHOR, SESSION + 1)
.unwrap();
});
let outcome = handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(outcome.opened, 0);
assert_eq!(outcome.closed, 0, "the incumbent must not be retired");
assert_eq!(
outcome.replies,
vec![ReplyRecord::CloseSlot {
slot: collider,
reason: CloseReason::ProtocolError
}],
"the newcomer is what fails, and it is told which slot id failed"
);
assert_eq!(registry.live_slots(peer()), 1);
assert!(
!incumbent_rx.is_disconnected(),
"the incumbent's consumer must not see its channel end"
);
assert_eq!(
registry.peer_bytes_used(peer()),
held_bytes,
"the incumbent's hold must still be charged to the peer budget — a \
silent eviction would have leaked it for the life of the epoch"
);
let payload = batch(1, 3, |encoder| {
encoder.push_data(incumbent, 1, &item(1)).unwrap();
});
handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(drain(&incumbent_rx), vec![item(1), item(2)]);
let rightful = slot(1, 0);
let payload = batch(1, 4, |encoder| {
encoder
.push_open_slot(rightful, 0, ANCHOR, SESSION + 1)
.unwrap();
});
let outcome = handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(outcome.opened, 1);
let payload = batch(1, 5, |encoder| {
encoder.push_data(rightful, 1, &item(9)).unwrap();
});
handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(drain(&rival_rx), vec![item(9)]);
}
#[test]
fn a_duplicate_open_retires_the_incumbent_through_the_ordinary_close() {
let config = config();
let registry = IngressRegistry::default();
let depth =
crate::streaming::messenger_mux::flow_control::slot_buffer_depth(config.initial_credit);
let (first_tx, first_rx) = flume::bounded(depth);
let (second_tx, second_rx) = flume::bounded(depth);
registry.register_bind(ANCHOR, SESSION, first_tx);
registry.register_bind(ANCHOR, SESSION + 1, second_tx);
let id = slot(0, 0);
open(®istry, &config, id, 1);
let payload = batch(1, 1, |encoder| {
encoder.push_data(id, 2, &item(2)).unwrap();
});
handle_batch(®istry, &config, None, peer(), &payload);
assert!(registry.peer_bytes_used(peer()) > 0);
let payload = batch(1, 2, |encoder| {
encoder.push_open_slot(id, 0, ANCHOR, SESSION + 1).unwrap();
});
let outcome = handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(outcome.opened, 1);
assert_eq!(
outcome.closed, 1,
"the incumbent was retired, not dropped on the floor"
);
assert_eq!(
registry.peer_bytes_used(peer()),
0,
"the incumbent's held bytes go back to the peer budget"
);
assert_eq!(
drain(&first_rx),
vec![cached_dropped().clone()],
"the incumbent's consumer is told why its stream ended"
);
let payload = batch(1, 3, |encoder| {
encoder.push_data(id, 1, &item(9)).unwrap();
});
handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(drain(&second_rx), vec![item(9)]);
assert_eq!(registry.live_slots(peer()), 1);
}
#[test]
fn records_for_a_slot_that_never_opened_are_dropped() {
let (registry, rx, config) = bound();
let payload = batch(1, 0, |encoder| {
encoder.push_data(slot(5, 0), 0, &item(1)).unwrap();
});
let outcome = handle_batch(®istry, &config, None, peer(), &payload);
assert!(outcome.replies.is_empty());
assert!(drain(&rx).is_empty());
}
#[test]
fn data_applies_in_frame_seq_order() {
let (registry, rx, config) = bound();
let id = slot(0, 0);
open(®istry, &config, id, 1);
let payload = batch(1, 1, |encoder| {
for n in 0..4u8 {
encoder
.push_data(id, u32::from(n) + 1, &item(n))
.expect("push data");
}
});
handle_batch(®istry, &config, None, peer(), &payload);
let frames = drain(&rx);
assert_eq!(frames.len(), 4);
for (n, frame) in frames.iter().enumerate() {
assert_eq!(frame, &item(n as u8), "frame {n} out of order");
}
}
#[test]
fn ahead_of_sequence_records_are_held_until_the_gap_closes() {
let (registry, rx, config) = bound();
let id = slot(0, 0);
open(®istry, &config, id, 1);
let payload = batch(1, 1, |encoder| {
encoder.push_data(id, 2, &item(2)).unwrap();
encoder.push_data(id, 3, &item(3)).unwrap();
});
handle_batch(®istry, &config, None, peer(), &payload);
assert!(
drain(&rx).is_empty(),
"nothing may be delivered while the gap is open"
);
let payload = batch(1, 2, |encoder| {
encoder.push_data(id, 1, &item(1)).unwrap();
});
handle_batch(®istry, &config, None, peer(), &payload);
let frames = drain(&rx);
assert_eq!(frames, vec![item(1), item(2), item(3)]);
}
#[test]
fn records_behind_the_sequence_are_dropped_as_duplicates() {
let (registry, rx, config) = bound();
let id = slot(0, 0);
open(®istry, &config, id, 1);
let payload = batch(1, 1, |encoder| {
encoder.push_data(id, 1, &item(1)).unwrap();
encoder.push_data(id, 1, &item(9)).unwrap();
});
handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(drain(&rx), vec![item(1)]);
assert_eq!(registry.live_slots(peer()), 1, "a duplicate is not a fault");
}
#[test]
fn hold_overflow_closes_that_slot_and_leaves_the_others_alone() {
let config = config();
let registry = IngressRegistry::default();
let depth =
crate::streaming::messenger_mux::flow_control::slot_buffer_depth(config.initial_credit);
let (tx_a, rx_a) = flume::bounded(depth);
let (tx_b, rx_b) = flume::bounded(depth);
registry.register_bind(ANCHOR, SESSION, tx_a);
registry.register_bind(ANCHOR, SESSION + 1, tx_b);
let a = slot(0, 0);
let b = slot(1, 0);
let payload = batch(1, 0, |encoder| {
encoder.push_open_slot(a, 0, ANCHOR, SESSION).unwrap();
encoder.push_open_slot(b, 0, ANCHOR, SESSION + 1).unwrap();
});
handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(registry.live_slots(peer()), 2);
let payload = batch(1, 1, |encoder| {
for seq in 2..=6u32 {
encoder.push_data(a, seq, &item(seq as u8)).unwrap();
}
encoder.push_data(b, 1, &item(42)).unwrap();
});
let outcome = handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(registry.live_slots(peer()), 1, "only slot A may close");
assert!(
outcome.replies.contains(&ReplyRecord::CloseSlot {
slot: a,
reason: CloseReason::ProtocolError
}),
"the owner is told which slot failed: {:?}",
outcome.replies
);
assert_eq!(
drain(&rx_a),
vec![cached_dropped().clone()],
"the consumer of the failed slot sees Dropped"
);
assert_eq!(drain(&rx_b), vec![item(42)], "slot B is untouched");
}
#[test]
fn a_record_at_the_wrong_generation_is_dropped_and_metered() {
let registry_metrics = prometheus::Registry::new();
let metrics = crate::observability::VeloMetrics::register(®istry_metrics).unwrap();
let mux_metrics = metrics.bind_mux();
let (registry, rx, config) = bound();
let id = slot(0, 3);
let payload = batch(1, 0, |encoder| {
encoder.push_open_slot(id, 0, ANCHOR, SESSION).unwrap();
});
handle_batch(®istry, &config, Some(&mux_metrics), peer(), &payload);
let payload = batch(1, 1, |encoder| {
encoder.push_data(slot(0, 2), 1, &item(1)).unwrap();
});
handle_batch(®istry, &config, Some(&mux_metrics), peer(), &payload);
assert!(
drain(&rx).is_empty(),
"a stale generation must never surface inside the stream now holding the index"
);
let snapshot =
crate::observability::test_helpers::MetricSnapshot::from_registry(®istry_metrics);
assert_eq!(
snapshot.counter("velo_streaming_mux_generation_mismatch_total", &[]),
1.0
);
}
#[test]
fn a_stale_epoch_batch_is_discarded_wholesale() {
let registry_metrics = prometheus::Registry::new();
let metrics = crate::observability::VeloMetrics::register(®istry_metrics).unwrap();
let mux_metrics = metrics.bind_mux();
let (registry, rx, config) = bound();
let id = slot(0, 0);
open(®istry, &config, id, 5);
let payload = batch(4, 0, |encoder| {
encoder.push_data(id, 1, &item(1)).unwrap();
encoder.push_data(id, 2, &item(2)).unwrap();
});
handle_batch(®istry, &config, Some(&mux_metrics), peer(), &payload);
assert!(drain(&rx).is_empty());
let snapshot =
crate::observability::test_helpers::MetricSnapshot::from_registry(®istry_metrics);
assert_eq!(
snapshot.counter(
"velo_streaming_mux_records_dropped_total",
&[("reason", "stale_epoch")]
),
2.0,
"the whole batch is dropped by header inspection, record count and all"
);
}
#[test]
fn a_newer_epoch_retires_the_old_slots_with_exactly_one_dropped() {
let (registry, rx, config) = bound();
let id = slot(0, 0);
open(®istry, &config, id, 1);
let payload = batch(1, 1, |encoder| {
encoder.push_data(id, 1, &item(1)).unwrap();
});
handle_batch(®istry, &config, None, peer(), &payload);
let payload = batch(2, 0, |encoder| {
encoder.push_data(slot(0, 0), 0, &item(2)).unwrap();
});
let outcome = handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(outcome.closed, 1);
assert_eq!(
registry.live_slots(peer()),
0,
"slots do not survive an epoch — that is what makes exactly-one-Dropped provable"
);
assert_eq!(drain(&rx), vec![item(1), cached_dropped().clone()]);
}
#[test]
fn terminal_then_close_delivers_the_terminal_and_injects_nothing() {
let (registry, rx, config) = bound();
let id = slot(0, 0);
open(®istry, &config, id, 1);
let payload = batch(1, 1, |encoder| {
encoder.push_data(id, 1, cached_finalized()).unwrap();
encoder
.push_close_slot(id, 2, CloseReason::TerminalSent)
.unwrap();
});
let outcome = handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(outcome.closed, 1);
assert_eq!(registry.live_slots(peer()), 0);
assert_eq!(
drain(&rx),
vec![cached_finalized().clone()],
"a terminal spends the reserve and closes without a spurious Dropped"
);
assert!(
rx.is_disconnected(),
"dropping the mux-side sender is what makes reader_pump exit its usual Err branch"
);
}
#[test]
fn a_terminal_gets_through_after_the_data_credit_is_spent() {
let config = MuxConfig {
initial_credit: 1,
..config()
};
let registry = IngressRegistry::default();
let (tx, rx) = flume::bounded(
crate::streaming::messenger_mux::flow_control::slot_buffer_depth(config.initial_credit),
);
registry.register_bind(ANCHOR, SESSION, tx);
let id = slot(0, 0);
open(®istry, &config, id, 1);
let payload = batch(1, 1, |encoder| {
encoder.push_data(id, 1, &item(1)).unwrap();
encoder.push_data(id, 2, cached_finalized()).unwrap();
encoder
.push_close_slot(id, 3, CloseReason::TerminalSent)
.unwrap();
});
let outcome = handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(outcome.closed, 1);
assert_eq!(
drain(&rx),
vec![item(1), cached_finalized().clone()],
"data exhaustion must never be what a slot fails to deliver its terminal on"
);
}
#[test]
fn a_terminal_close_defers_behind_records_still_in_the_hold() {
let (registry, rx, config) = bound();
let id = slot(0, 0);
open(®istry, &config, id, 1);
let payload = batch(1, 1, |encoder| {
encoder.push_data(id, 2, cached_finalized()).unwrap();
encoder
.push_close_slot(id, 3, CloseReason::TerminalSent)
.unwrap();
});
let outcome = handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(outcome.closed, 0, "the close waits for the gap to close");
assert_eq!(registry.live_slots(peer()), 1);
let payload = batch(1, 2, |encoder| {
encoder.push_data(id, 1, &item(1)).unwrap();
});
handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(
drain(&rx),
vec![item(1), cached_finalized().clone()],
"the consumer sees Finalized, not the Dropped an early close would have injected"
);
assert_eq!(registry.live_slots(peer()), 0);
}
#[test]
fn a_non_terminal_close_from_the_receiver_is_routed_to_the_batcher() {
let (registry, _rx, config) = bound();
let id = slot(0, 0);
open(®istry, &config, id, 1);
let payload = batch(1, 1, |encoder| {
encoder
.push_close_slot(id, 0, CloseReason::UnknownSlot)
.unwrap();
});
let outcome = handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(
outcome.peer_closes,
vec![(id, CloseReason::UnknownSlot)],
"direction is carried by the reason: anything but TerminalSent is about a slot we opened"
);
assert_eq!(
registry.live_slots(peer()),
1,
"our ingress slot is untouched"
);
}
#[test]
fn credit_is_returned_as_the_consumer_drains() {
let (registry, rx, config) = bound();
let id = slot(0, 0);
open(®istry, &config, id, 1);
let payload = batch(1, 1, |encoder| {
for seq in 1..=4u32 {
encoder.push_data(id, seq, &item(seq as u8)).unwrap();
}
});
let outcome = handle_batch(®istry, &config, None, peer(), &payload);
assert!(
outcome.replies.is_empty(),
"nothing has drained yet, so there is nothing to grant back"
);
assert_eq!(drain(&rx).len(), 4);
let replies = registry.sweep_credit(peer());
assert_eq!(
replies,
vec![ReplyRecord::CreditUpdate { slot: id, delta: 4 }],
"the sweep is what un-parks a sender whose peer has gone quiet"
);
}
#[test]
fn credit_is_withheld_while_the_slot_is_over_its_byte_watermark() {
let config = MuxConfig {
initial_credit: 4,
slot_byte_budget: 1,
..config()
};
let registry = IngressRegistry::default();
let (tx, rx) = flume::bounded(
crate::streaming::messenger_mux::flow_control::slot_buffer_depth(config.initial_credit),
);
registry.register_bind(ANCHOR, SESSION, tx);
let id = slot(0, 0);
open(®istry, &config, id, 1);
let payload = batch(1, 1, |encoder| {
for seq in 1..=2u32 {
encoder.push_data(id, seq, &item(seq as u8)).unwrap();
}
});
handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(drain(&rx).len(), 2);
assert_eq!(
registry.sweep_credit(peer()),
vec![ReplyRecord::CreditUpdate { slot: id, delta: 2 }]
);
}
#[test]
fn shutdown_retires_every_slot() {
let (registry, rx, config) = bound();
let id = slot(0, 0);
open(®istry, &config, id, 1);
assert_eq!(registry.shutdown(), 1);
assert_eq!(registry.live_slots(peer()), 0);
assert_eq!(drain(&rx), vec![cached_dropped().clone()]);
}
#[test]
fn a_heartbeat_record_reaches_the_consumer_as_a_heartbeat_frame() {
let (registry, rx, config) = bound();
let id = slot(0, 0);
open(®istry, &config, id, 1);
let payload = batch(1, 1, |encoder| {
encoder.push_heartbeat(id, 1).unwrap();
});
handle_batch(®istry, &config, None, peer(), &payload);
assert_eq!(
drain(&rx),
vec![crate::streaming::sender::cached_heartbeat().clone()],
"a heartbeat is a Data-class record: dropping one under saturation is \
the per-slot saturation signal reader_pump's watchdog watches for"
);
assert_eq!(RecordType::SlotHeartbeat.as_u8(), 4);
}