Commit e2d890af authored by David S. Miller's avatar David S. Miller

Merge branch 'selftests-xfail'

Jakub Kicinski says:

====================
selftests: kselftest_harness: support using xfail

When running selftests for our subsystem in our CI we'd like all
tests to pass. Currently some tests use SKIP for cases they
expect to fail, because the kselftest_harness limits the return
codes to pass/fail/skip. XFAIL which would be a great match
here cannot be used.

Remove the no_print handling and use vfork() to run the test in
a different process than the setup. This way we don't need to
pass "failing step" via the exit code. Further clean up the exit
codes so that we can use all KSFT_* values. Rewrite the result
printing to make handling XFAIL/XPASS easier. Support tests
declaring combinations of fixture + variant they expect to fail.

Merge plan is to put it on top of -rc6 and merge into net-next.
That way others should be able to pull the patches without
any networking changes.

v4:
 - rebase on top of Mickael's vfork() changes
v3: https://lore.kernel.org/all/20240220192235.2953484-1-kuba@kernel.org/
 - combine multiple series
 - change to "list of expected failures" rather than SKIP()-like handling
v2: https://lore.kernel.org/all/20240216002619.1999225-1-kuba@kernel.org/
 - fix alignment
follow up RFC: https://lore.kernel.org/all/20240216004122.2004689-1-kuba@kernel.org/
v1: https://lore.kernel.org/all/20240213154416.422739-1-kuba@kernel.org/
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7779f268 c05bf0e9
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
* ksft_test_result_skip(fmt, ...); * ksft_test_result_skip(fmt, ...);
* ksft_test_result_xfail(fmt, ...); * ksft_test_result_xfail(fmt, ...);
* ksft_test_result_error(fmt, ...); * ksft_test_result_error(fmt, ...);
* ksft_test_result_code(exit_code, test_name, fmt, ...);
* *
* When all tests are finished, clean up and exit the program with one of: * When all tests are finished, clean up and exit the program with one of:
* *
...@@ -254,6 +255,50 @@ static inline __printf(1, 2) void ksft_test_result_error(const char *msg, ...) ...@@ -254,6 +255,50 @@ static inline __printf(1, 2) void ksft_test_result_error(const char *msg, ...)
va_end(args); va_end(args);
} }
static inline __printf(3, 4)
void ksft_test_result_code(int exit_code, const char *test_name,
const char *msg, ...)
{
const char *tap_code = "ok";
const char *directive = "";
int saved_errno = errno;
va_list args;
switch (exit_code) {
case KSFT_PASS:
ksft_cnt.ksft_pass++;
break;
case KSFT_XFAIL:
directive = " # XFAIL ";
ksft_cnt.ksft_xfail++;
break;
case KSFT_XPASS:
directive = " # XPASS ";
ksft_cnt.ksft_xpass++;
break;
case KSFT_SKIP:
directive = " # SKIP ";
ksft_cnt.ksft_xskip++;
break;
case KSFT_FAIL:
default:
tap_code = "not ok";
ksft_cnt.ksft_fail++;
break;
}
/* Docs seem to call for double space if directive is absent */
if (!directive[0] && msg[0])
directive = " # ";
va_start(args, msg);
printf("%s %u %s%s", tap_code, ksft_test_num(), test_name, directive);
errno = saved_errno;
vprintf(msg, args);
printf("\n");
va_end(args);
}
static inline int ksft_exit_pass(void) static inline int ksft_exit_pass(void)
{ {
ksft_print_cnts(); ksft_print_cnts();
......
This diff is collapsed.
...@@ -307,7 +307,7 @@ TEST(ruleset_fd_transfer) ...@@ -307,7 +307,7 @@ TEST(ruleset_fd_transfer)
dir_fd = open("/tmp", O_RDONLY | O_DIRECTORY | O_CLOEXEC); dir_fd = open("/tmp", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
ASSERT_LE(0, dir_fd); ASSERT_LE(0, dir_fd);
ASSERT_EQ(0, close(dir_fd)); ASSERT_EQ(0, close(dir_fd));
_exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); _exit(_metadata->exit_code);
return; return;
} }
......
...@@ -23,62 +23,8 @@ ...@@ -23,62 +23,8 @@
#define __maybe_unused __attribute__((__unused__)) #define __maybe_unused __attribute__((__unused__))
#endif #endif
/* /* TEST_F_FORK() should not be used for new tests. */
* TEST_F_FORK() is useful when a test drop privileges but the corresponding #define TEST_F_FORK(fixture_name, test_name) TEST_F(fixture_name, test_name)
* FIXTURE_TEARDOWN() requires them (e.g. to remove files from a directory
* where write actions are denied). For convenience, FIXTURE_TEARDOWN() is
* also called when the test failed, but not when FIXTURE_SETUP() failed. For
* this to be possible, we must not call abort() but instead exit smoothly
* (hence the step print).
*/
/* clang-format off */
#define TEST_F_FORK(fixture_name, test_name) \
static void fixture_name##_##test_name##_child( \
struct __test_metadata *_metadata, \
FIXTURE_DATA(fixture_name) *self, \
const FIXTURE_VARIANT(fixture_name) *variant); \
TEST_F(fixture_name, test_name) \
{ \
int status; \
const pid_t child = fork(); \
if (child < 0) \
abort(); \
if (child == 0) { \
_metadata->no_print = 1; \
fixture_name##_##test_name##_child(_metadata, self, variant); \
if (_metadata->skip) \
_exit(255); \
if (_metadata->passed) \
_exit(0); \
_exit(_metadata->step); \
} \
if (child != waitpid(child, &status, 0)) \
abort(); \
if (WIFSIGNALED(status) || !WIFEXITED(status)) { \
_metadata->passed = 0; \
_metadata->step = 1; \
return; \
} \
switch (WEXITSTATUS(status)) { \
case 0: \
_metadata->passed = 1; \
break; \
case 255: \
_metadata->passed = 1; \
_metadata->skip = 1; \
break; \
default: \
_metadata->passed = 0; \
_metadata->step = WEXITSTATUS(status); \
break; \
} \
} \
static void fixture_name##_##test_name##_child( \
struct __test_metadata __attribute__((unused)) *_metadata, \
FIXTURE_DATA(fixture_name) __attribute__((unused)) *self, \
const FIXTURE_VARIANT(fixture_name) \
__attribute__((unused)) *variant)
/* clang-format on */
#ifndef landlock_create_ruleset #ifndef landlock_create_ruleset
static inline int static inline int
......
...@@ -1964,7 +1964,7 @@ static void test_execute(struct __test_metadata *const _metadata, const int err, ...@@ -1964,7 +1964,7 @@ static void test_execute(struct __test_metadata *const _metadata, const int err,
strerror(errno)); strerror(errno));
}; };
ASSERT_EQ(err, errno); ASSERT_EQ(err, errno);
_exit(_metadata->passed ? 2 : 1); _exit(__test_passed(_metadata) ? 2 : 1);
return; return;
} }
ASSERT_EQ(child, waitpid(child, &status, 0)); ASSERT_EQ(child, waitpid(child, &status, 0));
...@@ -3807,7 +3807,7 @@ TEST_F_FORK(ftruncate, open_and_ftruncate_in_different_processes) ...@@ -3807,7 +3807,7 @@ TEST_F_FORK(ftruncate, open_and_ftruncate_in_different_processes)
ASSERT_EQ(0, close(socket_fds[0])); ASSERT_EQ(0, close(socket_fds[0]));
_exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); _exit(_metadata->exit_code);
return; return;
} }
......
...@@ -539,7 +539,7 @@ static void test_bind_and_connect(struct __test_metadata *const _metadata, ...@@ -539,7 +539,7 @@ static void test_bind_and_connect(struct __test_metadata *const _metadata,
} }
EXPECT_EQ(0, close(connect_fd)); EXPECT_EQ(0, close(connect_fd));
_exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); _exit(_metadata->exit_code);
return; return;
} }
...@@ -834,7 +834,7 @@ TEST_F(protocol, connect_unspec) ...@@ -834,7 +834,7 @@ TEST_F(protocol, connect_unspec)
} }
EXPECT_EQ(0, close(connect_fd)); EXPECT_EQ(0, close(connect_fd));
_exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); _exit(_metadata->exit_code);
return; return;
} }
......
...@@ -314,7 +314,7 @@ TEST_F(hierarchy, trace) ...@@ -314,7 +314,7 @@ TEST_F(hierarchy, trace)
ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC)); ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
if (variant->domain_both) { if (variant->domain_both) {
create_domain(_metadata); create_domain(_metadata);
if (!_metadata->passed) if (!__test_passed(_metadata))
/* Aborts before forking. */ /* Aborts before forking. */
return; return;
} }
...@@ -375,7 +375,7 @@ TEST_F(hierarchy, trace) ...@@ -375,7 +375,7 @@ TEST_F(hierarchy, trace)
/* Waits for the parent PTRACE_ATTACH test. */ /* Waits for the parent PTRACE_ATTACH test. */
ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1)); ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1));
_exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); _exit(_metadata->exit_code);
return; return;
} }
...@@ -430,9 +430,10 @@ TEST_F(hierarchy, trace) ...@@ -430,9 +430,10 @@ TEST_F(hierarchy, trace)
/* Signals that the parent PTRACE_ATTACH test is done. */ /* Signals that the parent PTRACE_ATTACH test is done. */
ASSERT_EQ(1, write(pipe_parent[1], ".", 1)); ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
ASSERT_EQ(child, waitpid(child, &status, 0)); ASSERT_EQ(child, waitpid(child, &status, 0));
if (WIFSIGNALED(status) || !WIFEXITED(status) || if (WIFSIGNALED(status) || !WIFEXITED(status) ||
WEXITSTATUS(status) != EXIT_SUCCESS) WEXITSTATUS(status) != EXIT_SUCCESS)
_metadata->passed = 0; _metadata->exit_code = KSFT_FAIL;
} }
TEST_HARNESS_MAIN TEST_HARNESS_MAIN
...@@ -365,9 +365,6 @@ TEST_F(ip_local_port_range, late_bind) ...@@ -365,9 +365,6 @@ TEST_F(ip_local_port_range, late_bind)
__u32 range; __u32 range;
__u16 port; __u16 port;
if (variant->so_protocol == IPPROTO_SCTP)
SKIP(return, "SCTP doesn't support IP_BIND_ADDRESS_NO_PORT");
fd = socket(variant->so_domain, variant->so_type, 0); fd = socket(variant->so_domain, variant->so_type, 0);
ASSERT_GE(fd, 0) TH_LOG("socket failed"); ASSERT_GE(fd, 0) TH_LOG("socket failed");
...@@ -414,6 +411,9 @@ TEST_F(ip_local_port_range, late_bind) ...@@ -414,6 +411,9 @@ TEST_F(ip_local_port_range, late_bind)
ASSERT_TRUE(!err) TH_LOG("close failed"); ASSERT_TRUE(!err) TH_LOG("close failed");
} }
XFAIL_ADD(ip_local_port_range, ip4_stcp, late_bind);
XFAIL_ADD(ip_local_port_range, ip6_stcp, late_bind);
TEST_F(ip_local_port_range, get_port_range) TEST_F(ip_local_port_range, get_port_range)
{ {
__u16 lo, hi; __u16 lo, hi;
......
...@@ -1927,7 +1927,7 @@ TEST_F(tls_err, poll_partial_rec_async) ...@@ -1927,7 +1927,7 @@ TEST_F(tls_err, poll_partial_rec_async)
pfd.events = POLLIN; pfd.events = POLLIN;
EXPECT_EQ(poll(&pfd, 1, 20), 1); EXPECT_EQ(poll(&pfd, 1, 20), 1);
exit(!_metadata->passed); exit(!__test_passed(_metadata));
} }
} }
......
...@@ -1576,7 +1576,7 @@ void start_tracer(struct __test_metadata *_metadata, int fd, pid_t tracee, ...@@ -1576,7 +1576,7 @@ void start_tracer(struct __test_metadata *_metadata, int fd, pid_t tracee,
ASSERT_EQ(0, ret); ASSERT_EQ(0, ret);
} }
/* Directly report the status of our test harness results. */ /* Directly report the status of our test harness results. */
syscall(__NR_exit, _metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); syscall(__NR_exit, _metadata->exit_code);
} }
/* Common tracer setup/teardown functions. */ /* Common tracer setup/teardown functions. */
...@@ -1623,7 +1623,7 @@ void teardown_trace_fixture(struct __test_metadata *_metadata, ...@@ -1623,7 +1623,7 @@ void teardown_trace_fixture(struct __test_metadata *_metadata,
ASSERT_EQ(0, kill(tracer, SIGUSR1)); ASSERT_EQ(0, kill(tracer, SIGUSR1));
ASSERT_EQ(tracer, waitpid(tracer, &status, 0)); ASSERT_EQ(tracer, waitpid(tracer, &status, 0));
if (WEXITSTATUS(status)) if (WEXITSTATUS(status))
_metadata->passed = 0; _metadata->exit_code = KSFT_FAIL;
} }
} }
...@@ -3088,8 +3088,7 @@ TEST(syscall_restart) ...@@ -3088,8 +3088,7 @@ TEST(syscall_restart)
} }
/* Directly report the status of our test harness results. */ /* Directly report the status of our test harness results. */
syscall(__NR_exit, _metadata->passed ? EXIT_SUCCESS syscall(__NR_exit, _metadata->exit_code);
: EXIT_FAILURE);
} }
EXPECT_EQ(0, close(pipefd[0])); EXPECT_EQ(0, close(pipefd[0]));
...@@ -3174,7 +3173,7 @@ TEST(syscall_restart) ...@@ -3174,7 +3173,7 @@ TEST(syscall_restart)
ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
if (WIFSIGNALED(status) || WEXITSTATUS(status)) if (WIFSIGNALED(status) || WEXITSTATUS(status))
_metadata->passed = 0; _metadata->exit_code = KSFT_FAIL;
} }
TEST_SIGNAL(filter_flag_log, SIGSYS) TEST_SIGNAL(filter_flag_log, SIGSYS)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment