Skip to content

Commit 2b0bad2

Browse files
committed
Add tests for BPF Streams
Add tests for BPF Streams. The tests access both the stdout and stderr streams, and ensure the code works regardless of whether there is ready data. Signed-off-by: Emil Tsalapatis <[email protected]>
1 parent 0b4f33e commit 2b0bad2

File tree

3 files changed

+131
-1
lines changed

3 files changed

+131
-1
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
3+
4+
#include "vmlinux.h"
5+
#include <bpf/bpf_helpers.h>
6+
7+
/* Definition of can_loop taken from bpf_experimental.h. */
8+
#ifdef __BPF_FEATURE_MAY_GOTO
9+
#define can_loop \
10+
({ \
11+
__label__ l_break, l_continue; \
12+
bool ret = true; \
13+
asm volatile goto("may_goto %l[l_break]" :: ::l_break); \
14+
goto l_continue; \
15+
l_break: \
16+
ret = false; \
17+
l_continue:; \
18+
ret; \
19+
})
20+
#else
21+
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
22+
#define can_loop \
23+
({ \
24+
__label__ l_break, l_continue; \
25+
bool ret = true; \
26+
asm volatile goto("1:.byte 0xe5; \
27+
.byte 0; \
28+
.long ((%l[l_break] - 1b - 8) / 8) & 0xffff; \
29+
.short 0" :: ::l_break); \
30+
goto l_continue; \
31+
l_break: \
32+
ret = false; \
33+
l_continue:; \
34+
ret; \
35+
})
36+
#else
37+
#define can_loop \
38+
({ \
39+
__label__ l_break, l_continue; \
40+
bool ret = true; \
41+
asm volatile goto("1:.byte 0xe5; \
42+
.byte 0; \
43+
.long (((%l[l_break] - 1b - 8) / 8) & 0xffff) << 16; \
44+
.short 0" :: ::l_break); \
45+
goto l_continue; \
46+
l_break: \
47+
ret = false; \
48+
l_continue:; \
49+
ret; \
50+
})
51+
#endif
52+
#endif
53+
54+
volatile u64 i;
55+
56+
/* Trigger a may_goto timeout to emit a streams error. */
57+
SEC("syscall")
58+
int trigger_streams(void *ctx)
59+
{
60+
while (i == 0 && can_loop)
61+
;
62+
return 0;
63+
}
64+
65+
char LICENSE[] SEC("license") = "GPL";

libbpf-rs/tests/common/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use libbpf_rs::ObjectBuilder;
1515
use libbpf_rs::OpenObject;
1616
use libbpf_rs::ProgramMut;
1717

18-
1918
pub fn get_test_object_path(filename: &str) -> PathBuf {
2019
let mut path = PathBuf::new();
2120
// env!() macro fails at compile time if var not found

libbpf-rs/tests/test_streams.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//! Tests for BPF program streams (stdout/stderr).
2+
3+
mod common;
4+
5+
use std::io::Read;
6+
7+
use libbpf_rs::ProgramInput;
8+
use test_tag::tag;
9+
10+
use crate::common::get_prog_mut;
11+
use crate::common::get_test_object;
12+
13+
/// Test that we can read from a BPF program's stdout stream.
14+
///
15+
/// This test loads a BPF program that triggers the streams mechanism,
16+
/// runs it, and then attempts to read from the stdout stream.
17+
#[tag(root)]
18+
#[test]
19+
fn test_stream_stdout_read() {
20+
let mut obj = get_test_object("stream.bpf.o");
21+
let prog = get_prog_mut(&mut obj, "trigger_streams");
22+
23+
let input = ProgramInput::default();
24+
let _output = prog.test_run(input).unwrap();
25+
26+
let mut stdout = prog.stdout();
27+
let mut buf = [0u8; 1024];
28+
29+
// The read itself should succeed and return 0 bytes
30+
let result = stdout.read(&mut buf);
31+
assert!(
32+
result.is_ok(),
33+
"Failed to read from stdout stream: {:?}",
34+
result.err()
35+
);
36+
37+
let len = result.unwrap();
38+
assert!(
39+
len != 0,
40+
"Unexpectedly read {} characters from stderr stream",
41+
len
42+
);
43+
}
44+
45+
#[tag(root)]
46+
#[test]
47+
fn test_stream_stderr_read() {
48+
let mut obj = get_test_object("stream.bpf.o");
49+
let prog = get_prog_mut(&mut obj, "trigger_streams");
50+
51+
let input = ProgramInput::default();
52+
let _output = prog.test_run(input).unwrap();
53+
54+
let mut stderr = prog.stderr();
55+
let mut buf = [0u8; 1024];
56+
57+
// The read should successfully read a non-zero amount of bytes
58+
let result = stderr.read(&mut buf);
59+
assert!(
60+
result.is_ok(),
61+
"Failed to read from stderr stream: {:?}",
62+
result.err()
63+
);
64+
65+
assert!(result.unwrap() != 0, "No output from stderr stream");
66+
}

0 commit comments

Comments
 (0)