summaryrefslogtreecommitdiffstats
path: root/src/shared/tests.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:35:18 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:35:18 +0000
commitb750101eb236130cf056c675997decbac904cc49 (patch)
treea5df1a06754bdd014cb975c051c83b01c9a97532 /src/shared/tests.h
parentInitial commit. (diff)
downloadsystemd-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.h154
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)