use super::*;
use kevy_resp::Argv;
fn argv(parts: &[&[u8]]) -> Argv {
let mut a = Argv::default();
for p in parts {
a.push(p);
}
a
}
fn feed_with(n: usize) -> FeedSource {
let mut f = FeedSource::new(1, ReplicationSource::new(1 << 20));
for i in 0..n {
f.source_mut().push_mutation(&argv(&[b"SET", format!("k{i}").as_bytes(), b"v"]));
}
f
}
#[test]
fn read_serves_in_order_and_caps_at_max() {
let f = feed_with(5);
let frames = f.read(FeedPosition::new(1, 0), 3).unwrap();
assert_eq!(frames.len(), 3);
assert_eq!(frames[0].offset, 0);
assert_eq!(frames[2].offset, 2);
assert!(f.read(FeedPosition::new(1, 5), 10).unwrap().is_empty());
}
#[test]
fn stale_generation_resyncs_with_tail() {
let mut f = feed_with(3);
f.bump_generation();
let g2 = f.generation();
f.source_mut().push_mutation(&argv(&[b"SET", b"new", b"v"]));
match f.read(FeedPosition::new(1, 2), 10) {
Err(FeedRead::Resync { tail }) => assert_eq!(tail, FeedPosition::new(g2, 1)),
other => panic!("expected Resync, got {:?}", other.map(|v| v.len())),
}
let frames = f.read(FeedPosition::new(g2, 0), 10).unwrap();
assert_eq!(frames.len(), 1);
}
#[test]
fn generations_are_random_identities() {
let mut a = FeedSource::new(1, ReplicationSource::new(1 << 20));
let mut b = FeedSource::new(1, ReplicationSource::new(1 << 20));
a.bump_generation();
b.bump_generation();
assert_ne!(a.generation(), 0);
assert_ne!(a.generation(), 1, "old value must not repeat");
assert_ne!(a.generation(), 2, "a counter's next value is the collision");
assert_ne!(
a.generation(),
b.generation(),
"two nodes bumping from the same value must diverge"
);
let g = a.generation();
match a.read(FeedPosition::new(g.wrapping_add(1), 0), 10) {
Err(FeedRead::Resync { tail }) => assert_eq!(tail.generation, g),
other => panic!("expected Resync, got {:?}", other.map(|v| v.len())),
}
}
#[test]
fn future_cursors_rejected() {
let f = feed_with(2);
assert!(matches!(f.read(FeedPosition::new(3, 0), 1), Err(FeedRead::Resync { .. })));
assert!(matches!(f.read(FeedPosition::new(1, 99), 1), Err(FeedRead::Future)));
}
#[test]
fn evicted_offset_resyncs() {
let mut f = FeedSource::new(1, ReplicationSource::new(64));
for i in 0..50 {
f.source_mut().push_mutation(&argv(&[b"SET", format!("k{i}").as_bytes(), b"v"]));
}
match f.read(FeedPosition::new(1, 0), 10) {
Err(FeedRead::Resync { tail }) => assert_eq!(tail, FeedPosition::new(1, 50)),
other => panic!("expected Resync, got {:?}", other.map(|v| v.len())),
}
}