From: "Alexis Lothoré (eBPF Foundation)" <alexis.lothore@bootlin.com>
To: Andrii Nakryiko <andrii@kernel.org>,
Eduard Zingerman <eddyz87@gmail.com>,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Martin KaFai Lau <martin.lau@linux.dev>,
Song Liu <song@kernel.org>,
Yonghong Song <yonghong.song@linux.dev>,
John Fastabend <john.fastabend@gmail.com>,
KP Singh <kpsingh@kernel.org>,
Stanislav Fomichev <sdf@fomichev.me>,
Hao Luo <haoluo@google.com>, Jiri Olsa <jolsa@kernel.org>,
Shuah Khan <shuah@kernel.org>
Cc: ebpf@linuxfoundation.org,
"Bastien Curutchet" <bastien.curutchet@bootlin.com>,
"Thomas Petazzoni" <thomas.petazzoni@bootlin.com>,
linux-kernel@vger.kernel.org, bpf@vger.kernel.org,
linux-kselftest@vger.kernel.org,
"Alexis Lothoré (eBPF Foundation)" <alexis.lothore@bootlin.com>
Subject: [PATCH bpf-next 1/4] bpf/selftests: move assert macros into a dedicated header
Date: Wed, 14 Jan 2026 09:59:12 +0100 [thread overview]
Message-ID: <20260114-bpftool-tests-v1-1-cfab1cc9beaf@bootlin.com> (raw)
In-Reply-To: <20260114-bpftool-tests-v1-0-cfab1cc9beaf@bootlin.com>
The test_progs runner defines a large set of convenient assert macros to
perform all the tests. Writing a new runner involves rewriting some
macros if we want some basic testing features like standardized failure
log.
Export those assert macros from test_progs into a dedicated header so
that we can use those in any test_runner. The sole requirement to be
able to use those macros is to define a test__fail function in the
runner that will be called whenever an assert fails.
Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
---
tools/testing/selftests/bpf/assert_helpers.h | 231 +++++++++++++++++++++++++++
tools/testing/selftests/bpf/test_progs.h | 226 +-------------------------
2 files changed, 232 insertions(+), 225 deletions(-)
diff --git a/tools/testing/selftests/bpf/assert_helpers.h b/tools/testing/selftests/bpf/assert_helpers.h
new file mode 100644
index 000000000000..93ab5bf39431
--- /dev/null
+++ b/tools/testing/selftests/bpf/assert_helpers.h
@@ -0,0 +1,231 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#pragma once
+#include <stdio.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#define _CHECK(condition, tag, duration, format...) ({ \
+ int __ret = !!(condition); \
+ int __save_errno = errno; \
+ if (__ret) { \
+ test__fail(); \
+ fprintf(stdout, "%s:FAIL:%s ", __func__, tag); \
+ fprintf(stdout, ##format); \
+ } else { \
+ fprintf(stdout, "%s:PASS:%s %d nsec\n", \
+ __func__, tag, duration); \
+ } \
+ errno = __save_errno; \
+ __ret; \
+})
+
+#define CHECK_FAIL(condition) ({ \
+ int __ret = !!(condition); \
+ int __save_errno = errno; \
+ if (__ret) { \
+ test__fail(); \
+ fprintf(stdout, "%s:FAIL:%d\n", __func__, __LINE__); \
+ } \
+ errno = __save_errno; \
+ __ret; \
+})
+
+#define CHECK(condition, tag, format...) \
+ _CHECK(condition, tag, duration, format)
+#define CHECK_ATTR(condition, tag, format...) \
+ _CHECK(condition, tag, tattr.duration, format)
+
+#define ASSERT_FAIL(fmt, args...) ({ \
+ static int duration; \
+ CHECK(false, "", fmt"\n", ##args); \
+ false; \
+})
+
+#define ASSERT_TRUE(actual, name) ({ \
+ static int duration; \
+ bool ___ok = (actual); \
+ CHECK(!___ok, (name), "unexpected %s: got FALSE\n", (name)); \
+ ___ok; \
+})
+
+#define ASSERT_FALSE(actual, name) ({ \
+ static int duration; \
+ bool ___ok = !(actual); \
+ CHECK(!___ok, (name), "unexpected %s: got TRUE\n", (name)); \
+ ___ok; \
+})
+
+#define ASSERT_EQ(actual, expected, name) ({ \
+ static int duration; \
+ typeof(actual) ___act = (actual); \
+ typeof(expected) ___exp = (expected); \
+ bool ___ok = ___act == ___exp; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: actual %lld != expected %lld\n", \
+ (name), (long long)(___act), (long long)(___exp)); \
+ ___ok; \
+})
+
+#define ASSERT_NEQ(actual, expected, name) ({ \
+ static int duration; \
+ typeof(actual) ___act = (actual); \
+ typeof(expected) ___exp = (expected); \
+ bool ___ok = ___act != ___exp; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: actual %lld == expected %lld\n", \
+ (name), (long long)(___act), (long long)(___exp)); \
+ ___ok; \
+})
+
+#define ASSERT_LT(actual, expected, name) ({ \
+ static int duration; \
+ typeof(actual) ___act = (actual); \
+ typeof(expected) ___exp = (expected); \
+ bool ___ok = ___act < ___exp; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: actual %lld >= expected %lld\n", \
+ (name), (long long)(___act), (long long)(___exp)); \
+ ___ok; \
+})
+
+#define ASSERT_LE(actual, expected, name) ({ \
+ static int duration; \
+ typeof(actual) ___act = (actual); \
+ typeof(expected) ___exp = (expected); \
+ bool ___ok = ___act <= ___exp; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: actual %lld > expected %lld\n", \
+ (name), (long long)(___act), (long long)(___exp)); \
+ ___ok; \
+})
+
+#define ASSERT_GT(actual, expected, name) ({ \
+ static int duration; \
+ typeof(actual) ___act = (actual); \
+ typeof(expected) ___exp = (expected); \
+ bool ___ok = ___act > ___exp; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: actual %lld <= expected %lld\n", \
+ (name), (long long)(___act), (long long)(___exp)); \
+ ___ok; \
+})
+
+#define ASSERT_GE(actual, expected, name) ({ \
+ static int duration; \
+ typeof(actual) ___act = (actual); \
+ typeof(expected) ___exp = (expected); \
+ bool ___ok = ___act >= ___exp; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: actual %lld < expected %lld\n", \
+ (name), (long long)(___act), (long long)(___exp)); \
+ ___ok; \
+})
+
+#define ASSERT_STREQ(actual, expected, name) ({ \
+ static int duration; \
+ const char *___act = actual; \
+ const char *___exp = expected; \
+ bool ___ok = strcmp(___act, ___exp) == 0; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: actual '%s' != expected '%s'\n", \
+ (name), ___act, ___exp); \
+ ___ok; \
+})
+
+#define ASSERT_STRNEQ(actual, expected, len, name) ({ \
+ static int duration; \
+ const char *___act = actual; \
+ const char *___exp = expected; \
+ int ___len = len; \
+ bool ___ok = strncmp(___act, ___exp, ___len) == 0; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: actual '%.*s' != expected '%.*s'\n", \
+ (name), ___len, ___act, ___len, ___exp); \
+ ___ok; \
+})
+
+#define ASSERT_HAS_SUBSTR(str, substr, name) ({ \
+ static int duration; \
+ const char *___str = str; \
+ const char *___substr = substr; \
+ bool ___ok = strstr(___str, ___substr) != NULL; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: '%s' is not a substring of '%s'\n", \
+ (name), ___substr, ___str); \
+ ___ok; \
+})
+
+#define ASSERT_MEMEQ(actual, expected, len, name) ({ \
+ static int duration; \
+ const void *__act = actual; \
+ const void *__exp = expected; \
+ int __len = len; \
+ bool ___ok = memcmp(__act, __exp, __len) == 0; \
+ CHECK(!___ok, (name), "unexpected memory mismatch\n"); \
+ fprintf(stdout, "actual:\n"); \
+ hexdump("\t", __act, __len); \
+ fprintf(stdout, "expected:\n"); \
+ hexdump("\t", __exp, __len); \
+ ___ok; \
+})
+
+#define ASSERT_OK(res, name) ({ \
+ static int duration; \
+ long long ___res = (res); \
+ bool ___ok = ___res == 0; \
+ CHECK(!___ok, (name), "unexpected error: %lld (errno %d)\n", \
+ ___res, errno); \
+ ___ok; \
+})
+
+#define ASSERT_ERR(res, name) ({ \
+ static int duration; \
+ long long ___res = (res); \
+ bool ___ok = ___res < 0; \
+ CHECK(!___ok, (name), "unexpected success: %lld\n", ___res); \
+ ___ok; \
+})
+
+#define ASSERT_NULL(ptr, name) ({ \
+ static int duration; \
+ const void *___res = (ptr); \
+ bool ___ok = !___res; \
+ CHECK(!___ok, (name), "unexpected pointer: %p\n", ___res); \
+ ___ok; \
+})
+
+#define ASSERT_OK_PTR(ptr, name) ({ \
+ static int duration; \
+ const void *___res = (ptr); \
+ int ___err = libbpf_get_error(___res); \
+ bool ___ok = ___err == 0; \
+ CHECK(!___ok, (name), "unexpected error: %d\n", ___err); \
+ ___ok; \
+})
+
+#define ASSERT_ERR_PTR(ptr, name) ({ \
+ static int duration; \
+ const void *___res = (ptr); \
+ int ___err = libbpf_get_error(___res); \
+ bool ___ok = ___err != 0; \
+ CHECK(!___ok, (name), "unexpected pointer: %p\n", ___res); \
+ ___ok; \
+})
+
+#define ASSERT_OK_FD(fd, name) ({ \
+ static int duration; \
+ int ___fd = (fd); \
+ bool ___ok = ___fd >= 0; \
+ CHECK(!___ok, (name), "unexpected fd: %d (errno %d)\n", \
+ ___fd, errno); \
+ ___ok; \
+})
+
+#define ASSERT_ERR_FD(fd, name) ({ \
+ static int duration; \
+ int ___fd = (fd); \
+ bool ___ok = ___fd < 0; \
+ CHECK(!___ok, (name), "unexpected fd: %d\n", ___fd); \
+ ___ok; \
+})
+
diff --git a/tools/testing/selftests/bpf/test_progs.h b/tools/testing/selftests/bpf/test_progs.h
index eebfc18cdcd2..bb876d8f6bcc 100644
--- a/tools/testing/selftests/bpf/test_progs.h
+++ b/tools/testing/selftests/bpf/test_progs.h
@@ -42,6 +42,7 @@ typedef __u16 __sum16;
#include <bpf/bpf_endian.h>
#include "trace_helpers.h"
#include "testing_helpers.h"
+#include "assert_helpers.h"
enum verbosity {
VERBOSE_NONE,
@@ -195,231 +196,6 @@ void hexdump(const char *prefix, const void *buf, size_t len);
fprintf(stdout, ##format); \
})
-#define _CHECK(condition, tag, duration, format...) ({ \
- int __ret = !!(condition); \
- int __save_errno = errno; \
- if (__ret) { \
- test__fail(); \
- fprintf(stdout, "%s:FAIL:%s ", __func__, tag); \
- fprintf(stdout, ##format); \
- } else { \
- fprintf(stdout, "%s:PASS:%s %d nsec\n", \
- __func__, tag, duration); \
- } \
- errno = __save_errno; \
- __ret; \
-})
-
-#define CHECK_FAIL(condition) ({ \
- int __ret = !!(condition); \
- int __save_errno = errno; \
- if (__ret) { \
- test__fail(); \
- fprintf(stdout, "%s:FAIL:%d\n", __func__, __LINE__); \
- } \
- errno = __save_errno; \
- __ret; \
-})
-
-#define CHECK(condition, tag, format...) \
- _CHECK(condition, tag, duration, format)
-#define CHECK_ATTR(condition, tag, format...) \
- _CHECK(condition, tag, tattr.duration, format)
-
-#define ASSERT_FAIL(fmt, args...) ({ \
- static int duration = 0; \
- CHECK(false, "", fmt"\n", ##args); \
- false; \
-})
-
-#define ASSERT_TRUE(actual, name) ({ \
- static int duration = 0; \
- bool ___ok = (actual); \
- CHECK(!___ok, (name), "unexpected %s: got FALSE\n", (name)); \
- ___ok; \
-})
-
-#define ASSERT_FALSE(actual, name) ({ \
- static int duration = 0; \
- bool ___ok = !(actual); \
- CHECK(!___ok, (name), "unexpected %s: got TRUE\n", (name)); \
- ___ok; \
-})
-
-#define ASSERT_EQ(actual, expected, name) ({ \
- static int duration = 0; \
- typeof(actual) ___act = (actual); \
- typeof(expected) ___exp = (expected); \
- bool ___ok = ___act == ___exp; \
- CHECK(!___ok, (name), \
- "unexpected %s: actual %lld != expected %lld\n", \
- (name), (long long)(___act), (long long)(___exp)); \
- ___ok; \
-})
-
-#define ASSERT_NEQ(actual, expected, name) ({ \
- static int duration = 0; \
- typeof(actual) ___act = (actual); \
- typeof(expected) ___exp = (expected); \
- bool ___ok = ___act != ___exp; \
- CHECK(!___ok, (name), \
- "unexpected %s: actual %lld == expected %lld\n", \
- (name), (long long)(___act), (long long)(___exp)); \
- ___ok; \
-})
-
-#define ASSERT_LT(actual, expected, name) ({ \
- static int duration = 0; \
- typeof(actual) ___act = (actual); \
- typeof(expected) ___exp = (expected); \
- bool ___ok = ___act < ___exp; \
- CHECK(!___ok, (name), \
- "unexpected %s: actual %lld >= expected %lld\n", \
- (name), (long long)(___act), (long long)(___exp)); \
- ___ok; \
-})
-
-#define ASSERT_LE(actual, expected, name) ({ \
- static int duration = 0; \
- typeof(actual) ___act = (actual); \
- typeof(expected) ___exp = (expected); \
- bool ___ok = ___act <= ___exp; \
- CHECK(!___ok, (name), \
- "unexpected %s: actual %lld > expected %lld\n", \
- (name), (long long)(___act), (long long)(___exp)); \
- ___ok; \
-})
-
-#define ASSERT_GT(actual, expected, name) ({ \
- static int duration = 0; \
- typeof(actual) ___act = (actual); \
- typeof(expected) ___exp = (expected); \
- bool ___ok = ___act > ___exp; \
- CHECK(!___ok, (name), \
- "unexpected %s: actual %lld <= expected %lld\n", \
- (name), (long long)(___act), (long long)(___exp)); \
- ___ok; \
-})
-
-#define ASSERT_GE(actual, expected, name) ({ \
- static int duration = 0; \
- typeof(actual) ___act = (actual); \
- typeof(expected) ___exp = (expected); \
- bool ___ok = ___act >= ___exp; \
- CHECK(!___ok, (name), \
- "unexpected %s: actual %lld < expected %lld\n", \
- (name), (long long)(___act), (long long)(___exp)); \
- ___ok; \
-})
-
-#define ASSERT_STREQ(actual, expected, name) ({ \
- static int duration = 0; \
- const char *___act = actual; \
- const char *___exp = expected; \
- bool ___ok = strcmp(___act, ___exp) == 0; \
- CHECK(!___ok, (name), \
- "unexpected %s: actual '%s' != expected '%s'\n", \
- (name), ___act, ___exp); \
- ___ok; \
-})
-
-#define ASSERT_STRNEQ(actual, expected, len, name) ({ \
- static int duration = 0; \
- const char *___act = actual; \
- const char *___exp = expected; \
- int ___len = len; \
- bool ___ok = strncmp(___act, ___exp, ___len) == 0; \
- CHECK(!___ok, (name), \
- "unexpected %s: actual '%.*s' != expected '%.*s'\n", \
- (name), ___len, ___act, ___len, ___exp); \
- ___ok; \
-})
-
-#define ASSERT_HAS_SUBSTR(str, substr, name) ({ \
- static int duration = 0; \
- const char *___str = str; \
- const char *___substr = substr; \
- bool ___ok = strstr(___str, ___substr) != NULL; \
- CHECK(!___ok, (name), \
- "unexpected %s: '%s' is not a substring of '%s'\n", \
- (name), ___substr, ___str); \
- ___ok; \
-})
-
-#define ASSERT_MEMEQ(actual, expected, len, name) ({ \
- static int duration = 0; \
- const void *__act = actual; \
- const void *__exp = expected; \
- int __len = len; \
- bool ___ok = memcmp(__act, __exp, __len) == 0; \
- CHECK(!___ok, (name), "unexpected memory mismatch\n"); \
- fprintf(stdout, "actual:\n"); \
- hexdump("\t", __act, __len); \
- fprintf(stdout, "expected:\n"); \
- hexdump("\t", __exp, __len); \
- ___ok; \
-})
-
-#define ASSERT_OK(res, name) ({ \
- static int duration = 0; \
- long long ___res = (res); \
- bool ___ok = ___res == 0; \
- CHECK(!___ok, (name), "unexpected error: %lld (errno %d)\n", \
- ___res, errno); \
- ___ok; \
-})
-
-#define ASSERT_ERR(res, name) ({ \
- static int duration = 0; \
- long long ___res = (res); \
- bool ___ok = ___res < 0; \
- CHECK(!___ok, (name), "unexpected success: %lld\n", ___res); \
- ___ok; \
-})
-
-#define ASSERT_NULL(ptr, name) ({ \
- static int duration = 0; \
- const void *___res = (ptr); \
- bool ___ok = !___res; \
- CHECK(!___ok, (name), "unexpected pointer: %p\n", ___res); \
- ___ok; \
-})
-
-#define ASSERT_OK_PTR(ptr, name) ({ \
- static int duration = 0; \
- const void *___res = (ptr); \
- int ___err = libbpf_get_error(___res); \
- bool ___ok = ___err == 0; \
- CHECK(!___ok, (name), "unexpected error: %d\n", ___err); \
- ___ok; \
-})
-
-#define ASSERT_ERR_PTR(ptr, name) ({ \
- static int duration = 0; \
- const void *___res = (ptr); \
- int ___err = libbpf_get_error(___res); \
- bool ___ok = ___err != 0; \
- CHECK(!___ok, (name), "unexpected pointer: %p\n", ___res); \
- ___ok; \
-})
-
-#define ASSERT_OK_FD(fd, name) ({ \
- static int duration = 0; \
- int ___fd = (fd); \
- bool ___ok = ___fd >= 0; \
- CHECK(!___ok, (name), "unexpected fd: %d (errno %d)\n", \
- ___fd, errno); \
- ___ok; \
-})
-
-#define ASSERT_ERR_FD(fd, name) ({ \
- static int duration = 0; \
- int ___fd = (fd); \
- bool ___ok = ___fd < 0; \
- CHECK(!___ok, (name), "unexpected fd: %d\n", ___fd); \
- ___ok; \
-})
-
#define SYS(goto_label, fmt, ...) \
({ \
char cmd[1024]; \
--
2.52.0
next prev parent reply other threads:[~2026-01-14 8:59 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-14 8:59 [PATCH bpf-next 0/4] selftests/bpf: add a new runner for bpftool tests Alexis Lothoré (eBPF Foundation)
2026-01-14 8:59 ` Alexis Lothoré (eBPF Foundation) [this message]
2026-01-15 11:33 ` [PATCH bpf-next 1/4] bpf/selftests: move assert macros into a dedicated header Quentin Monnet
2026-01-14 8:59 ` [PATCH bpf-next 2/4] bpf/selftests: introduce bptool test runner and a first test Alexis Lothoré (eBPF Foundation)
2026-01-15 11:32 ` Quentin Monnet
2026-01-16 8:14 ` Alexis Lothoré
2026-01-14 8:59 ` [PATCH bpf-next 3/4] selftests/bpf: add bpftool map manipulations tests Alexis Lothoré (eBPF Foundation)
2026-01-15 11:36 ` Quentin Monnet
2026-01-14 8:59 ` [PATCH bpf-next 4/4] selftests/bpf: remove converted bpftool test scripts Alexis Lothoré (eBPF Foundation)
2026-01-15 11:37 ` Quentin Monnet
2026-01-15 17:58 ` [PATCH bpf-next 0/4] selftests/bpf: add a new runner for bpftool tests Andrii Nakryiko
2026-01-16 7:57 ` Alexis Lothoré
2026-01-16 22:20 ` Andrii Nakryiko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260114-bpftool-tests-v1-1-cfab1cc9beaf@bootlin.com \
--to=alexis.lothore@bootlin.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bastien.curutchet@bootlin.com \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=ebpf@linuxfoundation.org \
--cc=eddyz87@gmail.com \
--cc=haoluo@google.com \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=kpsingh@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=sdf@fomichev.me \
--cc=shuah@kernel.org \
--cc=song@kernel.org \
--cc=thomas.petazzoni@bootlin.com \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox