From: Thomas Haller <thaller@redhat.com>
To: NetFilter <netfilter-devel@vger.kernel.org>
Cc: Thomas Haller <thaller@redhat.com>
Subject: [PATCH nft v2 5/5] tests/unit: add unit tests for libnftables
Date: Sun, 5 Nov 2023 16:08:41 +0100 [thread overview]
Message-ID: <20231105150955.349966-6-thaller@redhat.com> (raw)
In-Reply-To: <20231105150955.349966-1-thaller@redhat.com>
We have a lot of tests/shell tests, that use the "nft" binary and we
have python tests that can use the public API of "libnftables.so".
However, it's useful to also write unit tests, that can test the
internal C code more immediately.
Since no such tests infrastructure exist yet, it would be cumbersome to
write such a test. Add two new test binaries, that can be used as a
place for such tests. Currently there are no real tests there, it's only
to show how it works, and that those dummy tests pass (including that
linking and execution passes).
To access the internals, build an intermediate static library
"src/libnftables-static.la", which then makes up the public, dynamic
"src/libnftables.la" library. Add two tests:
- tests/unit/test-libnftables-static
- tests/unit/test-libnftables
The former statically links with "src/libnftables-static.la" and can test
internal API from headers under "include/*.h". The latter dynamically
links with "src/libnftables.la", and can only test the public API from
"includes/nftables/libnftables.h".
You can run the unit tests alone with `make check-TESTS`. There is also
`make check-unit`, which aliases `check-TESTS` target. Calling
`VALGRIND=y make check` works as expected.
Also add a LOG_COMPILER script "tools/test-runner.sh". This wraps the
execution of the tests. Even for manual testing, you likely don't want
to run "tests/unit/test-*" executables directly, but rather
$ ./tools/test-runner.sh tests/unit/test-libnftables
This sets up an unshared namespace, honors VALGRIND=y to run the
test under valgrind, handles libtool, and supports options --make
and --gdb. It also set up some environment variables that will be useful
for some tests (e.g. "$SRCDIR").
Also, ignore some build artifacts from top level gitignore file. The
build artifacts like "*.o" will not only be found under "src/". Move
those patterns.
Signed-off-by: Thomas Haller <thaller@redhat.com>
---
.gitignore | 15 +-
Makefile.am | 75 ++++++++-
src/.gitignore | 5 -
tests/unit/nft-test.h | 14 ++
tests/unit/test-libnftables-static.c | 16 ++
tests/unit/test-libnftables.c | 21 +++
tools/test-runner.sh | 235 +++++++++++++++++++++++++++
7 files changed, 365 insertions(+), 16 deletions(-)
create mode 100644 tests/unit/nft-test.h
create mode 100644 tests/unit/test-libnftables-static.c
create mode 100644 tests/unit/test-libnftables.c
create mode 100755 tools/test-runner.sh
diff --git a/.gitignore b/.gitignore
index a62e31f31c6b..369678a13987 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,11 @@
-# Generated by autoconf/configure/automake
+# Generated by autoconf/configure/automake/make
*.m4
+*.la
+*.lo
+*.o
+.deps/
.dirstamp
+.libs/
Makefile
Makefile.in
stamp-h1
@@ -20,7 +25,13 @@ libtool
# Generated by tests
*.payload.got
-tests/build/tests.log
+test-suite.log
+tests/**/*.log
+tests/**/*.trs
+tests/**/*.valgrind-log
+
+tests/unit/test-libnftables
+tests/unit/test-libnftables-static
# Debian package build temporary files
build-stamp
diff --git a/Makefile.am b/Makefile.am
index 396bf3fa2c22..d4656c340a31 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -31,12 +31,18 @@ lib_LTLIBRARIES =
noinst_LTLIBRARIES =
sbin_PROGRAMS =
check_PROGRAMS =
+noinst_PROGRAMS =
check_LTLIBRARIES =
dist_man_MANS =
CLEANFILES =
+TESTS =
+test_programs =
check_local =
check_more =
+TESTS_ENVIRONMENT = VERBOSE="$(V)" NFT_TEST_MAKE=n
+LOG_COMPILER = "$(srcdir)/tools/test-runner.sh" --srcdir "$(abs_srcdir)" --builddir "$(abs_builddir)" --
+
###############################################################################
pkginclude_HEADERS = \
@@ -205,11 +211,9 @@ endif
###############################################################################
-lib_LTLIBRARIES += src/libnftables.la
+noinst_LTLIBRARIES += src/libnftables-static.la
-src_libnftables_la_SOURCES = \
- src/libnftables.map \
- \
+src_libnftables_static_la_SOURCES = \
src/cache.c \
src/cmd.c \
src/ct.c \
@@ -257,20 +261,36 @@ src_libnftables_la_SOURCES = \
$(NULL)
if BUILD_JSON
-src_libnftables_la_SOURCES += \
+src_libnftables_static_la_SOURCES += \
src/json.c \
src/parser_json.c \
$(NULL)
endif
+src_libnftables_static_la_LIBADD = \
+ src/libparser.la \
+ $(LIBMINIGMP_LIBS) \
+ $(LIBMNL_LIBS) \
+ $(LIBNFTNL_LIBS) \
+ $(XTABLES_LIBS) \
+ $(JANSSON_LIBS) \
+ $(NULL)
+
+###############################################################################
+
+lib_LTLIBRARIES += src/libnftables.la
+
+src_libnftables_la_SOURCES = \
+ src/libnftables.map \
+ $(NULL)
+
src_libnftables_la_LDFLAGS = \
-version-info "${libnftables_LIBVERSION}" \
-Wl,--version-script="$(srcdir)/src//libnftables.map" \
$(NULL)
src_libnftables_la_LIBADD = \
- src/libparser.la \
- $(LIBMINIGMP_LIBS) \
+ src/libnftables-static.la \
$(LIBMNL_LIBS) \
$(LIBNFTNL_LIBS) \
$(XTABLES_LIBS) \
@@ -303,6 +323,22 @@ examples_nft_json_file_LDADD = src/libnftables.la
###############################################################################
+EXTRA_DIST += tests/unit/nft-test.h
+
+###############################################################################
+
+test_programs += tests/unit/test-libnftables-static
+
+tests_unit_test_libnftables_static_LDADD = src/libnftables-static.la
+
+###############################################################################
+
+test_programs += tests/unit/test-libnftables
+
+tests_unit_test_libnftables_LDADD = src/libnftables.la
+
+###############################################################################
+
if BUILD_MAN
dist_man_MANS += \
@@ -390,6 +426,16 @@ dist_pkgsysconf_DATA = \
###############################################################################
+EXTRA_DIST += \
+ tests/build \
+ tests/json_echo \
+ tests/monitor \
+ tests/py \
+ tests/shell \
+ $(NULL)
+
+###############################################################################
+
EXTRA_DIST += \
py/pyproject.toml \
py/setup.cfg \
@@ -403,7 +449,6 @@ EXTRA_DIST += \
EXTRA_DIST += \
files \
- tests \
tools \
$(NULL)
@@ -412,12 +457,24 @@ pkgconfig_DATA = libnftables.pc
###############################################################################
-build-all: all $(check_PROGRAMS) $(check_LTLIBRARIES)
+check_PROGRAMS += $(test_programs)
+
+TESTS += $(test_programs)
+
+###############################################################################
+
+build-all: all $(check_PROGRAMS) $(test_programs) $(check_LTLIBRARIES)
.PHONY: build-all
###############################################################################
+check-unit: check-TESTS
+
+.PHONY: check-unit
+
+###############################################################################
+
check-tree:
"$(srcdir)/tools/check-tree.sh"
diff --git a/src/.gitignore b/src/.gitignore
index 2d907425cbb0..f34105c6cda4 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,8 +1,3 @@
-*.la
-*.lo
-*.o
-.deps/
-.libs/
nft
parser_bison.c
parser_bison.h
diff --git a/tests/unit/nft-test.h b/tests/unit/nft-test.h
new file mode 100644
index 000000000000..cab97b42c669
--- /dev/null
+++ b/tests/unit/nft-test.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef __NFT_TEST__H__
+#define __NFT_TEST__H__
+
+#undef NDEBUG
+
+#include <nft.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#endif /* __NFT_TEST__H__ */
diff --git a/tests/unit/test-libnftables-static.c b/tests/unit/test-libnftables-static.c
new file mode 100644
index 000000000000..e34fcfd77f39
--- /dev/null
+++ b/tests/unit/test-libnftables-static.c
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "nft-test.h"
+
+#include <datatype.h>
+
+static void test_datatype(void)
+{
+ assert(!datatype_lookup(-1));
+}
+
+int main(int argc, char **argv)
+{
+ test_datatype();
+ return 0;
+}
diff --git a/tests/unit/test-libnftables.c b/tests/unit/test-libnftables.c
new file mode 100644
index 000000000000..100558cd5e0f
--- /dev/null
+++ b/tests/unit/test-libnftables.c
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "nft-test.h"
+
+#include <nftables/libnftables.h>
+
+static void test_nft_ctx(void)
+{
+ struct nft_ctx *ctx;
+
+ ctx = nft_ctx_new(0);
+ assert(ctx);
+
+ nft_ctx_free(ctx);
+}
+
+int main(int argc, char **argv)
+{
+ test_nft_ctx();
+ return 0;
+}
diff --git a/tools/test-runner.sh b/tools/test-runner.sh
new file mode 100755
index 000000000000..bb10af19c3a4
--- /dev/null
+++ b/tools/test-runner.sh
@@ -0,0 +1,235 @@
+#!/bin/bash
+
+set -e
+
+die() {
+ printf '%s\n' "$*"
+ exit 1
+}
+
+usage() {
+ echo " $0 [OPTIONS] TEST"
+ echo
+ echo "Run TEST. Usually you don't want to run our unit test"
+ echo "executables directly, but via this wrapper script."
+ echo
+ echo "This script is also the LOG_COMPILER for all TESTS in Makefile.am."
+ echo
+ echo "Interesting Options:"
+ echo " -V|--valgrind: Sets VALGRIND=y to run under valgrind."
+ echo " -G|--gdb: Sets NFT_TEST_WRAPPER=gdb to start a debugger."
+ echo " -m|--make: Sets NFT_TEST_MAKE=y to build the test first."
+ echo "Other options:"
+ echo " --srcdir dir: Sets SRCDIR=dir."
+ echo " --builddir dir: Sets BUILDDIR=dir."
+ echo " --: Separates options from test name."
+ echo " TEST: the path of the test executable to run."
+ echo
+ echo "Environment variables:"
+ echo " SRCDIR: set to \$(srcdir) of the project."
+ echo " BUILDDIR: set to \$(builddir) of the project."
+ echo " VERBOSE: for verbose output."
+ echo " VALGRIND: if set to TRUE, run the test under valgrind. NFT_TEST_UNDER_VALGRIND is ignored."
+ echo " NFT_TEST_UNSHARE_CMD: override the command to unshare the netns."
+ echo " Set to empty to not unshare."
+ echo " NFT_TEST_WRAPPER: usually empty. For manual testing, this is prepended to TEST."
+ echo " Set for example got \"gdb\"."
+ echo " NFT_TEST_MAKE: if true, call \`make\` on the test first."
+}
+
+usage_and_die() {
+ usage
+ echo
+ die "$@"
+}
+
+TIMESTAMP=$(date '+%Y%m%d-%H%M%S.%3N')
+
+as_bool() {
+ if [ "$#" -eq 0 ] ; then
+ return 1
+ fi
+ case "$1" in
+ y|Y|yes|Yes|YES|1|true|True|TRUE)
+ return 0
+ ;;
+ n|N|no|No|NO|0|false|False|FALSE)
+ return 1
+ ;;
+ *)
+ # Fallback to the next in the list.
+ shift
+ rc=0
+ as_bool "$@" || rc=$?
+ return "$rc"
+ esac
+}
+
+as_bool_str() {
+ if as_bool "$@" ; then
+ printf y
+ else
+ printf n
+ fi
+}
+
+# Honored environment variables from the caller (and their defaults).
+# SRCDIR unset
+# BUILDDIR unset
+# TMP unset
+# NFT_TEST_VALGRIND_OPTS unset
+VERBOSE="$(as_bool_str "$VERBOSE")"
+VALGRIND="$(as_bool_str "$VALGRIND")"
+NFT_TEST_UNSHARE_CMD="${NFT_TEST_UNSHARE_CMD-unshare -m -U --map-root-user -n}"
+NFT_TEST_WRAPPER="${NFT_TEST_WRAPPER}"
+NFT_TEST_MAKE="$(as_bool_str "$NFT_TEST_MAKE")"
+
+unset TEST
+
+while [ $# -gt 0 ] ; do
+ A="$1"
+ shift
+ case "$A" in
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ --srcdir)
+ SRCDIR="$1"
+ shift
+ ;;
+ --builddir)
+ BUILDDIR="$1"
+ shift
+ ;;
+ -V|--valgrind)
+ VALGRIND=y
+ ;;
+ -G|--gdb)
+ NFT_TEST_WRAPPER=gdb
+ ;;
+ -m|--make)
+ NFT_TEST_MAKE=y
+ ;;
+ --)
+ if [ $# -ne 1 ] ; then
+ usage_and_die "Requires a TEST argument after --"
+ fi
+ TEST="$1"
+ shift
+ ;;
+ *)
+ if [ -n "${TEST+x}" ] ; then
+ usage_and_die "Unknown argument \"$A\""
+ fi
+ TEST="$A"
+ ;;
+ esac
+done
+
+if [ -z "$TEST" ] ; then
+ usage_and_die "Missing test argument. See --help"
+fi
+
+if [ -z "${SRCDIR+x}" ] ; then
+ SRCDIR="$(readlink -f "$(dirname "$0")/..")"
+fi
+if [ ! -d "$SRCDIR" ] ; then
+ die "Invalid \$SRCDIR=\"$SRCDIR\""
+fi
+
+if [ -z "${BUILDDIR+x}" ] ; then
+ re='^(.*/|)(tests/unit/test-[^/]*)$'
+ if [[ "$TEST" =~ $re ]] ; then
+ BUILDDIR="$(readlink -f "${BASH_REMATCH[1]:-.}")" || :
+ else
+ BUILDDIR="$SRCDIR"
+ fi
+fi
+if [ ! -d "$BUILDDIR" ] ; then
+ die "Invalid \$BUILDDIR=\"$BUILDDIR\""
+fi
+
+export TESTDIR="$(dirname "$TEST")"
+export SRCDIR
+export BUILDDIR
+
+if [ "$VALGRIND" = y ] ; then
+ export NFT_TEST_UNDER_VALGRIND=1
+fi
+
+run_unit() {
+ local TEST="$1"
+
+ if [ "$NFT_TEST_MAKE" = y ] ; then
+ local d="$(readlink -f "$BUILDDIR")"
+ local tf="$(readlink -f "$TEST")"
+ local t="${tf#$d/}"
+
+ if [ "$tf" != "$d/$t" ] ; then
+ die "Cannot detect paths for making \"$TEST\" in \"$BUILDDIR\" (\"$d\" and \"$t\")"
+ fi
+ # Don't use "make -C" to avoid the extra "Entering/Leaving directory" messages
+ ( cd "$d" && make "$t" ) || die "Making \"$TEST\" failed"
+ fi
+
+ if [ "$VALGRIND" != y ] ; then
+ rc_test=0
+ $NFT_TEST_UNSHARE_CMD \
+ libtool \
+ --mode=execute \
+ $NFT_TEST_WRAPPER \
+ "$TEST" || rc_test=$?
+ if [ "$rc_test" -ne 0 -a "$rc_test" -ne 77 ] ; then
+ die "exec \"$TEST\" failed with exit code $rc_test"
+ fi
+ exit "$rc_test"
+ fi
+
+ LOGFILE="$TEST.valgrind-log"
+
+ rc_test=0
+ $NFT_TEST_UNSHARE_CMD \
+ libtool \
+ --mode=execute \
+ valgrind \
+ --quiet \
+ --error-exitcode=122 \
+ --leak-check=full \
+ --gen-suppressions=all \
+ --num-callers=100 \
+ --log-file="$LOGFILE" \
+ --vgdb-prefix="${TMP:-/tmp}/vgdb-pipe-nft-test-runner-$TIMESTAMP-$$" \
+ $NFT_TEST_VALGRIND_OPTS \
+ "$TEST" \
+ || rc_test=$?
+
+ if [ -s "$LOGFILE" ] ; then
+ if [ "$rc_test" -eq 0 -o "$rc_test" -eq 122 ] ; then
+ echo "valgrind failed. Logfile at \"$LOGFILE\" :"
+ cat "$LOGFILE"
+ rc_test=122
+ else
+ echo "valgrind also failed. Check logfile at \"$LOGFILE\""
+ fi
+ elif [ ! -f "$LOGFILE" ] ; then
+ echo "valgrind logfile \"$LOGFILE\" missing"
+ if [ "$rc_test" -eq 0 ] ; then
+ rc_test=122
+ fi
+ else
+ rm -rf "$LOGFILE"
+ fi
+
+ exit "$rc_test"
+}
+
+case "$TEST" in
+ tests/unit/test-* | \
+ */tests/unit/test-* )
+ run_unit "$TEST"
+ ;;
+ *)
+ die "Unrecognized test \"$TEST\""
+ ;;
+esac
--
2.41.0
next prev parent reply other threads:[~2023-11-05 15:12 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-05 15:08 [PATCH nft v2 0/5] add infrastructure for unit tests Thomas Haller
2023-11-05 15:08 ` [PATCH nft v2 1/5] build: add basic "check-{local,more,all}" and "build-all" make targets Thomas Haller
2023-11-05 15:08 ` [PATCH nft v2 2/5] build: add `make check-build` to run `./tests/build/run-tests.sh` Thomas Haller
2023-11-05 15:08 ` [PATCH nft v2 3/5] build: add `make check-tree` to check consistency of source tree Thomas Haller
2023-11-05 15:08 ` [PATCH nft v2 4/5] build: cleanup if-blocks for conditional compilation in "Makefile.am" Thomas Haller
2023-11-05 15:08 ` Thomas Haller [this message]
2023-11-21 12:34 ` [PATCH nft v2 0/5] add infrastructure for unit tests Thomas Haller
2023-11-21 12:37 ` Pablo Neira Ayuso
2023-12-06 7:53 ` Thomas Haller
2023-12-06 17:18 ` Pablo Neira Ayuso
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=20231105150955.349966-6-thaller@redhat.com \
--to=thaller@redhat.com \
--cc=netfilter-devel@vger.kernel.org \
/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;
as well as URLs for NNTP newsgroup(s).