diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 15:35:18 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 15:35:18 +0000 |
commit | b750101eb236130cf056c675997decbac904cc49 (patch) | |
tree | a5df1a06754bdd014cb975c051c83b01c9a97532 /src/shared/tests.h | |
parent | Initial commit. (diff) | |
download | systemd-b750101eb236130cf056c675997decbac904cc49.tar.xz systemd-b750101eb236130cf056c675997decbac904cc49.zip |
Adding upstream version 252.22.upstream/252.22
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/shared/tests.h')
-rw-r--r-- | src/shared/tests.h | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/src/shared/tests.h b/src/shared/tests.h new file mode 100644 index 0000000..a02bfa8 --- /dev/null +++ b/src/shared/tests.h @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include <stdbool.h> + +#include "sd-daemon.h" + +#include "macro.h" +#include "static-destruct.h" +#include "util.h" + +static inline bool manager_errno_skip_test(int r) { + return IN_SET(abs(r), + EPERM, + EACCES, + EADDRINUSE, + EHOSTDOWN, + ENOENT, + ENOMEDIUM /* cannot determine cgroup */ + ); +} + +char* setup_fake_runtime_dir(void); +int enter_cgroup_subroot(char **ret_cgroup); +int enter_cgroup_root(char **ret_cgroup); +int get_testdata_dir(const char *suffix, char **ret); +const char* get_catalog_dir(void); +bool slow_tests_enabled(void); +void test_setup_logging(int level); + +#define log_tests_skipped(fmt, ...) \ + ({ \ + log_notice("%s: " fmt ", skipping tests.", \ + program_invocation_short_name, \ + ##__VA_ARGS__); \ + EXIT_TEST_SKIP; \ + }) + +#define log_tests_skipped_errno(error, fmt, ...) \ + ({ \ + log_notice_errno(error, \ + "%s: " fmt ", skipping tests: %m", \ + program_invocation_short_name, \ + ##__VA_ARGS__); \ + EXIT_TEST_SKIP; \ + }) + +int write_tmpfile(char *pattern, const char *contents); + +bool have_namespaces(void); + +/* We use the small but non-trivial limit here */ +#define CAN_MEMLOCK_SIZE (512 * 1024U) +bool can_memlock(void); + +#define TEST_REQ_RUNNING_SYSTEMD(x) \ + if (sd_booted() > 0) { \ + x; \ + } else { \ + printf("systemd not booted, skipping '%s'\n", #x); \ + } + +/* Provide a convenient way to check if we're running in CI. */ +const char *ci_environment(void); + +typedef struct TestFunc { + union f { + void (*void_func)(void); + int (*int_func)(void); + } f; + const char * const name; + bool has_ret:1; + bool sd_booted:1; +} TestFunc; + +/* See static-destruct.h for an explanation of how this works. */ +#define REGISTER_TEST(func, ...) \ + _Pragma("GCC diagnostic ignored \"-Wattributes\"") \ + _section_("SYSTEMD_TEST_TABLE") _alignptr_ _used_ _retain_ _variable_no_sanitize_address_ \ + static const TestFunc UNIQ_T(static_test_table_entry, UNIQ) = { \ + .f = (union f) &(func), \ + .name = STRINGIFY(func), \ + .has_ret = __builtin_types_compatible_p(typeof((union f){}.int_func), typeof(&(func))), \ + ##__VA_ARGS__ \ + } + +extern const TestFunc _weak_ __start_SYSTEMD_TEST_TABLE[]; +extern const TestFunc _weak_ __stop_SYSTEMD_TEST_TABLE[]; + +#define TEST(name, ...) \ + static void test_##name(void); \ + REGISTER_TEST(test_##name, ##__VA_ARGS__); \ + static void test_##name(void) + +#define TEST_RET(name, ...) \ + static int test_##name(void); \ + REGISTER_TEST(test_##name, ##__VA_ARGS__); \ + static int test_##name(void) + +static inline int run_test_table(void) { + int r = EXIT_SUCCESS; + + if (!__start_SYSTEMD_TEST_TABLE) + return r; + + const TestFunc *t = ALIGN_PTR(__start_SYSTEMD_TEST_TABLE); + while (t < __stop_SYSTEMD_TEST_TABLE) { + + if (t->sd_booted && sd_booted() <= 0) { + log_info("/* systemd not booted, skipping %s */", t->name); + if (t->has_ret && r == EXIT_SUCCESS) + r = EXIT_TEST_SKIP; + } else { + log_info("/* %s */", t->name); + + if (t->has_ret) { + int r2 = t->f.int_func(); + if (r == EXIT_SUCCESS) + r = r2; + } else + t->f.void_func(); + } + + t = ALIGN_PTR(t + 1); + } + + return r; +} + +#define DEFINE_TEST_MAIN_FULL(log_level, intro, outro) \ + int main(int argc, char *argv[]) { \ + int (*_intro)(void) = intro; \ + int (*_outro)(void) = outro; \ + int _r, _q; \ + test_setup_logging(log_level); \ + save_argc_argv(argc, argv); \ + _r = _intro ? _intro() : EXIT_SUCCESS; \ + if (_r == EXIT_SUCCESS) \ + _r = run_test_table(); \ + _q = _outro ? _outro() : EXIT_SUCCESS; \ + static_destruct(); \ + if (_r < 0) \ + return EXIT_FAILURE; \ + if (_r != EXIT_SUCCESS) \ + return _r; \ + if (_q < 0) \ + return EXIT_FAILURE; \ + return _q; \ + } + +#define DEFINE_TEST_MAIN_WITH_INTRO(log_level, intro) \ + DEFINE_TEST_MAIN_FULL(log_level, intro, NULL) +#define DEFINE_TEST_MAIN(log_level) \ + DEFINE_TEST_MAIN_FULL(log_level, NULL, NULL) |