1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//! Plan 158 syscall batching — `syscall_batch` feature must not
//! change the observable dump output vs. the un-batched path.
//!
//! Mirrors §5.5 of `plans/166-0.17-integration-test-backfill-plan.md`.
//! The check is parity, not perf: same set of links, same order, same
//! count. This guards against batch buffer-reuse bugs that would
//! corrupt the parsed stream.
//!
//! The file is *not* `cfg(feature = "syscall_batch")`-gated: the
//! eager and streaming dump paths must give the same count
//! regardless of the feature flag. The CI runner is responsible for
//! invoking with `--features lab,syscall_batch` once Plan 140 lands.
use nlink::netlink::link::DummyLink;
use tokio_stream::StreamExt;
use crate::common::TestNamespace;
#[tokio::test]
async fn batch_and_eager_dumps_observe_same_link_count() -> nlink::Result<()> {
require_root!();
nlink::require_modules!("dummy");
let ns = TestNamespace::new("batch-parity")?;
let conn = ns.connection()?;
// Populate enough links to span at least one syscall batch
// (32 frames per `recvmmsg` on the streaming path).
for i in 0..40 {
conn.add_link(DummyLink::new(format!("d{i}"))).await?;
}
let eager = conn.get_links().await?;
let mut streamed = 0usize;
let mut stream = conn.stream_links().await?;
while let Some(item) = stream.next().await {
item?;
streamed += 1;
}
assert_eq!(
eager.len(),
streamed,
"syscall_batch parity: eager + streaming dumps must observe \
identical link counts (eager={}, streaming={})",
eager.len(),
streamed,
);
Ok(())
}