diff --git a/src/shared/tests.h b/src/shared/tests.h index 85f9463f9b..07e05bf267 100644 --- a/src/shared/tests.h +++ b/src/shared/tests.h @@ -2,11 +2,15 @@ #pragma once #include +#include #include "sd-daemon.h" #include "argv-util.h" #include "macro.h" +#include "process-util.h" +#include "rlimit-util.h" +#include "signal-util.h" #include "static-destruct.h" #include "strv.h" @@ -249,11 +253,10 @@ static inline int run_test_table(void) { #define ASSERT_STREQ(expr1, expr2) \ ({ \ - const char* _expr1 = (expr1); \ - const char* _expr2 = (expr2); \ - if (strcmp(_expr1, _expr2) != 0) { \ + const char *_expr1 = (expr1), *_expr2 = (expr2); \ + if (!streq_ptr(_expr1, _expr2)) { \ log_error("%s:%i: Assertion failed: expected \"%s == %s\", but \"%s != %s\"", \ - PROJECT_FILE, __LINE__, #expr1, #expr2, _expr1, _expr2); \ + PROJECT_FILE, __LINE__, #expr1, #expr2, strnull(_expr1), strnull(_expr2)); \ abort(); \ } \ }) @@ -350,3 +353,26 @@ static inline int run_test_table(void) { abort(); \ } \ }) + +#define ASSERT_SIGNAL(expr, signal) \ + ({ \ + ASSERT_TRUE(SIGNAL_VALID(signal)); \ + siginfo_t _siginfo = {}; \ + int _pid = fork(); \ + ASSERT_OK(_pid); \ + if (_pid == 0) { \ + /* Speed things up by never even attempting to generate a coredump */ \ + (void) prctl(PR_SET_DUMPABLE, 0); \ + /* But still set an rlimit just in case */ \ + (void) setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(0)); \ + expr; \ + _exit(EXIT_SUCCESS); \ + } \ + (void) wait_for_terminate(_pid, &_siginfo); \ + if (_siginfo.si_status != signal) { \ + log_error("%s:%i: Assertion failed: \"%s\" died with signal %s, but %s was expected", \ + PROJECT_FILE, __LINE__, #expr, signal_to_string(_siginfo.si_status), \ + signal_to_string(signal)); \ + abort(); \ + } \ + }) diff --git a/src/test/test-macro.c b/src/test/test-macro.c index 78503a5660..017a20f540 100644 --- a/src/test/test-macro.c +++ b/src/test/test-macro.c @@ -1105,4 +1105,61 @@ TEST(u64_multiply_safe) { assert_se(u64_multiply_safe(UINT64_MAX, UINT64_MAX) == 0); } +TEST(ASSERT) { + char *null = NULL; + + ASSERT_OK(0); + ASSERT_OK(255); + ASSERT_OK(printf("Hello world\n")); + ASSERT_SIGNAL(ASSERT_OK(-1), SIGABRT); + ASSERT_SIGNAL(ASSERT_OK(-ENOANO), SIGABRT); + + ASSERT_TRUE(true); + ASSERT_TRUE(255); + ASSERT_TRUE(getpid()); + ASSERT_SIGNAL(ASSERT_TRUE(1 == 0), SIGABRT); + + ASSERT_FALSE(false); + ASSERT_FALSE(1 == 0); + ASSERT_SIGNAL(ASSERT_FALSE(1 > 0), SIGABRT); + + ASSERT_NULL(NULL); + ASSERT_SIGNAL(ASSERT_NULL(signal_to_string(SIGINT)), SIGABRT); + + ASSERT_NOT_NULL(signal_to_string(SIGTERM)); + ASSERT_SIGNAL(ASSERT_NOT_NULL(NULL), SIGABRT); + + ASSERT_STREQ(NULL, null); + ASSERT_STREQ("foo", "foo"); + ASSERT_SIGNAL(ASSERT_STREQ(null, "bar"), SIGABRT); + ASSERT_SIGNAL(ASSERT_STREQ("foo", "bar"), SIGABRT); + + ASSERT_EQ(0, 0); + ASSERT_EQ(-1, -1); + ASSERT_SIGNAL(ASSERT_EQ(255, -1), SIGABRT); + + ASSERT_GE(0, 0); + ASSERT_GE(1, -1); + ASSERT_SIGNAL(ASSERT_GE(-1, 1), SIGABRT); + + ASSERT_LE(0, 0); + ASSERT_LE(-1, 1); + ASSERT_SIGNAL(ASSERT_LE(1, -1), SIGABRT); + + ASSERT_NE(0, (int64_t) UINT_MAX); + ASSERT_NE(-1, 1); + ASSERT_SIGNAL(ASSERT_NE(0, 0), SIGABRT); + ASSERT_SIGNAL(ASSERT_NE(-1, -1), SIGABRT); + + ASSERT_GT(1, 0); + ASSERT_GT(1, -1); + ASSERT_SIGNAL(ASSERT_GT(0, 0), SIGABRT); + ASSERT_SIGNAL(ASSERT_GT(-1, 1), SIGABRT); + + ASSERT_LT(0, 1); + ASSERT_LT(-1, 1); + ASSERT_SIGNAL(ASSERT_LT(0, 0), SIGABRT); + ASSERT_SIGNAL(ASSERT_LT(1, -1), SIGABRT); +} + DEFINE_TEST_MAIN(LOG_INFO); diff --git a/test/TEST-24-CRYPTSETUP/test.sh b/test/TEST-24-CRYPTSETUP/test.sh index 757c39a449..93b447f583 100755 --- a/test/TEST-24-CRYPTSETUP/test.sh +++ b/test/TEST-24-CRYPTSETUP/test.sh @@ -18,6 +18,9 @@ KERNEL_OPTIONS=( "luks.name=$PART_UUID=$DM_NAME" "luks.key=$PART_UUID=/keyfile:LABEL=varcrypt_keydev" "luks.options=$PART_UUID=x-initrd.attach" + # Forward journal to console to make debugging easier (or possible at all) if we fail to bring the + # encrypted /var up during boot + "systemd.journald.forward_to_console=1" ) KERNEL_APPEND+=" ${KERNEL_OPTIONS[*]}" QEMU_OPTIONS+=" -drive format=raw,cache=unsafe,file=${STATEDIR:?}/keydev.img" diff --git a/test/test-functions b/test/test-functions index c62cf3d521..33575d3b3a 100644 --- a/test/test-functions +++ b/test/test-functions @@ -662,6 +662,7 @@ run_nspawn() { "--directory=${1:?}" "--setenv=SYSTEMD_UNIT_PATH=/usr/lib/systemd/tests/testdata/testsuite-$2.units:/usr/lib/systemd/tests/testdata/units:" "--machine=TEST-$TESTID" + "--background=''" ) local kernel_params=( "$PATH_TO_INIT" diff --git a/test/test-shutdown.py b/test/test-shutdown.py index f496122f80..870c1e269f 100755 --- a/test/test-shutdown.py +++ b/test/test-shutdown.py @@ -15,9 +15,16 @@ def run(args): ret = 1 logger = logging.getLogger("test-shutdown") + logfile = None + + if args.logfile: + logger.debug("Logging pexpect IOs to %s", args.logfile) + logfile = open(args.logfile, 'w') + elif args.verbose: + logfile = sys.stdout logger.info("spawning test") - console = pexpect.spawn(args.command, args.arg, env={ + console = pexpect.spawn(args.command, args.arg, logfile=logfile, env={ "TERM": "linux", }, encoding='utf-8', timeout=60) @@ -27,12 +34,6 @@ def run(args): logger.info("waiting for login prompt") console.expect('H login: ', 10) - if args.logfile: - logger.debug("Logging pexpect IOs to %s", args.logfile) - console.logfile = open(args.logfile, 'w') - elif args.verbose: - console.logfile = sys.stdout - logger.info("log in and start screen") console.sendline('root') console.expect('bash.*# ', 10) @@ -42,6 +43,10 @@ def run(args): console.send('c') console.expect('screen1 ', 10) + logger.info('wait for the machine to fully boot') + console.sendline('systemctl is-system-running --wait') + console.expect(r'\b(running|degraded)\b', 60) + # console.interact() console.sendline('tty') diff --git a/test/units/testsuite-04.journal-gatewayd.sh b/test/units/testsuite-04.journal-gatewayd.sh index a58d76e2ee..4bd3c79a4d 100755 --- a/test/units/testsuite-04.journal-gatewayd.sh +++ b/test/units/testsuite-04.journal-gatewayd.sh @@ -27,37 +27,37 @@ systemctl start systemd-journal-gatewayd.socket # /browse # We should get redirected to /browse by default -curl -Lfs http://localhost:19531 | grep -qF "Journal" -curl -Lfs http://localhost:19531/browse | grep -qF "Journal" -(! curl -Lfs http://localhost:19531/foo/bar/baz) -(! curl -Lfs http://localhost:19531/foo/../../../bar/../baz) +curl -LSfs http://localhost:19531 | grep -F "Journal" >/dev/null +curl -LSfs http://localhost:19531/browse | grep -F "Journal" >/dev/null +(! curl -LSfs http://localhost:19531/foo/bar/baz) +(! curl -LSfs http://localhost:19531/foo/../../../bar/../baz) # /entries # Accept: text/plain should be the default -curl -Lfs http://localhost:19531/entries | \ - grep -qE " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" -curl -Lfs --header "Accept: text/plain" http://localhost:19531/entries | \ - grep -qE " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" -curl -Lfs --header "Accept: application/json" http://localhost:19531/entries | \ +curl -LSfs http://localhost:19531/entries | \ + grep -E " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" >/dev/null +curl -LSfs --header "Accept: text/plain" http://localhost:19531/entries | \ + grep -E " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" >/dev/null +curl -LSfs --header "Accept: application/json" http://localhost:19531/entries | \ jq -se ".[] | select(.MESSAGE == \"$TEST_MESSAGE\")" -curl -Lfs --header "Accept: application/json" http://localhost:19531/entries?boot | \ +curl -LSfs --header "Accept: application/json" http://localhost:19531/entries?boot | \ jq -se ".[] | select(.MESSAGE == \"$TEST_MESSAGE\")" -curl -Lfs --header "Accept: application/json" http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" | \ +curl -LSfs --header "Accept: application/json" http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" | \ jq -se "length == 1 and select(.[].MESSAGE == \"$TEST_MESSAGE\")" # Show 10 entries starting from $BOOT_CURSOR, skip the first 5 -curl -Lfs --header "Accept: application/json" --header "Range: entries=$BOOT_CURSOR:5:10" http://localhost:19531/entries | \ +curl -LSfs --header "Accept: application/json" --header "Range: entries=$BOOT_CURSOR:5:10" http://localhost:19531/entries | \ jq -se "length == 10" # Check if the specified cursor refers to an existing entry and return just that entry -curl -Lfs --header "Accept: application/json" --header "Range: entries=$TEST_CURSOR" http://localhost:19531/entries?discrete | \ +curl -LSfs --header "Accept: application/json" --header "Range: entries=$TEST_CURSOR" http://localhost:19531/entries?discrete | \ jq -se "length == 1 and select(.[].MESSAGE == \"$TEST_MESSAGE\")" # Check entry is present (resp. absent) when filtering by timestamp -curl -Lfs --header "Range: realtime=$BEFORE_TIMESTAMP:" http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" | \ - grep -qE " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" -curl -Lfs --header "Range: realtime=:$AFTER_TIMESTAMP" http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" | \ - grep -qE " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" -curl -Lfs --header "Accept: application/json" --header "Range: realtime=:$BEFORE_TIMESTAMP" http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" | \ +curl -LSfs --header "Range: realtime=$BEFORE_TIMESTAMP:" http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" | \ + grep -E " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" >/dev/null +curl -LSfs --header "Range: realtime=:$AFTER_TIMESTAMP" http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" | \ + grep -E " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" >/dev/null +curl -LSfs --header "Accept: application/json" --header "Range: realtime=:$BEFORE_TIMESTAMP" http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" | \ jq -se "length == 0" -curl -Lfs --header "Accept: application/json" --header "Range: realtime=$AFTER_TIMESTAMP:" http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" | \ +curl -LSfs --header "Accept: application/json" --header "Range: realtime=$AFTER_TIMESTAMP:" http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" | \ jq -se "length == 0" # Check positive and negative skip when filtering by timestamp echo "-= This is a second test message =-" | systemd-cat -t "$TEST_TAG" @@ -67,18 +67,18 @@ echo "-= This is a third test message =-" | systemd-cat -t "$TEST_TAG" journalctl --sync sleep 1 END_TIMESTAMP="$(date +%s)" -curl -Lfs --header "Accept: application/json" --header "Range: realtime=$BEFORE_TIMESTAMP::1:1" http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" | \ +curl -LSfs --header "Accept: application/json" --header "Range: realtime=$BEFORE_TIMESTAMP::1:1" http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" | \ jq -se "length == 1 and select(.[].__CURSOR == \"$TEST2_CURSOR\")" -curl -Lfs --header "Accept: application/json" --header "Range: realtime=$END_TIMESTAMP::-1:1" http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" | \ +curl -LSfs --header "Accept: application/json" --header "Range: realtime=$END_TIMESTAMP::-1:1" http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" | \ jq -se "length == 1 and select(.[].__CURSOR == \"$TEST2_CURSOR\")" # No idea how to properly parse this (jq won't cut it), so let's at least do some sanity checks that every # line is either empty or begins with data: -curl -Lfs --header "Accept: text/event-stream" http://localhost:19531/entries | \ +curl -LSfs --header "Accept: text/event-stream" http://localhost:19531/entries | \ awk '!/^(data: \{.+\}|)$/ { exit 1; }' # Same thing as journalctl --output=export mkdir /tmp/remote-journal -curl -Lfs --header "Accept: application/vnd.fdo.journal" http://localhost:19531/entries | \ +curl -LSfs --header "Accept: application/vnd.fdo.journal" http://localhost:19531/entries | \ /usr/lib/systemd/systemd-journal-remote --output=/tmp/remote-journal/system.journal --split-mode=none - journalctl --directory=/tmp/remote-journal -t "$TEST_TAG" --grep "$TEST_MESSAGE" rm -rf /tmp/remote-journal/* @@ -90,13 +90,13 @@ journalctl --directory=/tmp/remote-journal -t "$TEST_TAG" --grep "$TEST_MESSAGE" rm -rf /tmp/remote-journal # /machine -curl -Lfs http://localhost:19531/machine | jq +curl -LSfs http://localhost:19531/machine | jq # /fields -curl -Lfs http://localhost:19531/fields/MESSAGE | grep -qE -- "$TEST_MESSAGE" -curl -Lfs http://localhost:19531/fields/_TRANSPORT -(! curl -Lfs http://localhost:19531/fields) -(! curl -Lfs http://localhost:19531/fields/foo-bar-baz) +curl -LSfs http://localhost:19531/fields/MESSAGE | grep -E -- "$TEST_MESSAGE" >/dev/null +curl -LSfs http://localhost:19531/fields/_TRANSPORT +(! curl -LSfs http://localhost:19531/fields) +(! curl -LSfs http://localhost:19531/fields/foo-bar-baz) systemctl stop systemd-journal-gatewayd.{socket,service} @@ -133,13 +133,13 @@ GATEWAYD_PID=$! sleep 1 # Do a limited set of tests, since the underlying code should be the same past the HTTPS transport -curl -Lfsk https://localhost:19531 | grep -qF "Journal" -curl -Lfsk https://localhost:19531/entries | \ - grep -qE " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" -curl -Lfsk --header "Accept: application/json" https://localhost:19531/entries | \ +curl -LSfsk https://localhost:19531 | grep -F "Journal" >/dev/null +curl -LSfsk https://localhost:19531/entries | \ + grep -E " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" >/dev/null +curl -LSfsk --header "Accept: application/json" https://localhost:19531/entries | \ jq -se ".[] | select(.MESSAGE == \"$TEST_MESSAGE\")" -curl -Lfsk https://localhost:19531/machine | jq -curl -Lfsk https://localhost:19531/fields/_TRANSPORT +curl -LSfsk https://localhost:19531/machine | jq +curl -LSfsk https://localhost:19531/fields/_TRANSPORT kill "$GATEWAYD_PID" @@ -161,18 +161,18 @@ curl --fail-with-body --upload-file "$GATEWAYD_FILE" -L http://localhost:19531/u (! grep '[^[:print:]]' "$OUT") rm -rf "$OUT" -curl -Lfs http://localhost:19531/browse | grep -qF "Journal" +curl -LSfs http://localhost:19531/browse | grep -F "Journal" >/dev/null # Nuke the file behind the /browse endpoint mv /usr/share/systemd/gatewayd/browse.html /usr/share/systemd/gatewayd/browse.html.bak (! curl --fail-with-body -L http://localhost:19531/browse) mv /usr/share/systemd/gatewayd/browse.html.bak /usr/share/systemd/gatewayd/browse.html -curl -Lfs http://localhost:19531/browse | grep -qF "Journal" +curl -LSfs http://localhost:19531/browse | grep -F "Journal" >/dev/null # Nuke the journal file mv "$GATEWAYD_FILE" "$GATEWAYD_FILE.bak" (! curl --fail-with-body -L http://localhost:19531/fields/_PID) mv "$GATEWAYD_FILE.bak" "$GATEWAYD_FILE" -curl -Lfs http://localhost:19531/fields/_PID +curl -LSfs http://localhost:19531/fields/_PID systemctl stop test-gatewayd.{socket,service} rm -f "$GATEWAYD_FILE" diff --git a/test/units/testsuite-75.sh b/test/units/testsuite-75.sh index 199a23964d..fc29e642fb 100755 --- a/test/units/testsuite-75.sh +++ b/test/units/testsuite-75.sh @@ -719,7 +719,9 @@ if command -v nft >/dev/null; then sleep 2 drop_dns_outbound_traffic set +e - run dig stale1.unsigned.test -t A + # Make sure we give sd-resolved enough time to timeout (5-10s) before giving up + # See: https://github.com/systemd/systemd/issues/31639#issuecomment-2009152617 + run dig +tries=1 +timeout=15 stale1.unsigned.test -t A set -eux grep -qE "no servers could be reached" "$RUN_OUT" nft flush ruleset @@ -738,7 +740,8 @@ if command -v nft >/dev/null; then grep -qE "NOERROR" "$RUN_OUT" sleep 2 drop_dns_outbound_traffic - run dig stale1.unsigned.test -t A + # Make sure we give sd-resolved enough time to timeout (5-10s) and serve the stale data (see above) + run dig +tries=1 +timeout=15 stale1.unsigned.test -t A grep -qE "NOERROR" "$RUN_OUT" grep -qE "10.0.0.112" "$RUN_OUT"