1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 #pragma once
3
4 #include <stdbool.h>
5
6 #include "sd-daemon.h"
7
8 #include "macro.h"
9 #include "static-destruct.h"
10 #include "util.h"
11
manager_errno_skip_test(int r)12 static inline bool manager_errno_skip_test(int r) {
13 return IN_SET(abs(r),
14 EPERM,
15 EACCES,
16 EADDRINUSE,
17 EHOSTDOWN,
18 ENOENT,
19 ENOMEDIUM /* cannot determine cgroup */
20 );
21 }
22
23 char* setup_fake_runtime_dir(void);
24 int enter_cgroup_subroot(char **ret_cgroup);
25 int enter_cgroup_root(char **ret_cgroup);
26 int get_testdata_dir(const char *suffix, char **ret);
27 const char* get_catalog_dir(void);
28 bool slow_tests_enabled(void);
29 void test_setup_logging(int level);
30 int log_tests_skipped(const char *message);
31 int log_tests_skipped_errno(int r, const char *message);
32
33 int write_tmpfile(char *pattern, const char *contents);
34
35 bool have_namespaces(void);
36
37 /* We use the small but non-trivial limit here */
38 #define CAN_MEMLOCK_SIZE (512 * 1024U)
39 bool can_memlock(void);
40
41 #define TEST_REQ_RUNNING_SYSTEMD(x) \
42 if (sd_booted() > 0) { \
43 x; \
44 } else { \
45 printf("systemd not booted, skipping '%s'\n", #x); \
46 }
47
48 /* Provide a convenient way to check if we're running in CI. */
49 const char *ci_environment(void);
50
51 typedef struct TestFunc {
52 union f {
53 void (*void_func)(void);
54 int (*int_func)(void);
55 } f;
56 const char * const name;
57 bool has_ret:1;
58 bool sd_booted:1;
59 } TestFunc;
60
61 /* See static-destruct.h for an explanation of how this works. */
62 #define REGISTER_TEST(func, ...) \
63 _Pragma("GCC diagnostic ignored \"-Wattributes\"") \
64 _section_("SYSTEMD_TEST_TABLE") _alignptr_ _used_ _retain_ _variable_no_sanitize_address_ \
65 static const TestFunc UNIQ_T(static_test_table_entry, UNIQ) = { \
66 .f = (union f) &(func), \
67 .name = STRINGIFY(func), \
68 .has_ret = __builtin_types_compatible_p(typeof((union f){}.int_func), typeof(&(func))), \
69 ##__VA_ARGS__ \
70 }
71
72 extern const TestFunc _weak_ __start_SYSTEMD_TEST_TABLE[];
73 extern const TestFunc _weak_ __stop_SYSTEMD_TEST_TABLE[];
74
75 #define TEST(name, ...) \
76 static void test_##name(void); \
77 REGISTER_TEST(test_##name, ##__VA_ARGS__); \
78 static void test_##name(void)
79
80 #define TEST_RET(name, ...) \
81 static int test_##name(void); \
82 REGISTER_TEST(test_##name, ##__VA_ARGS__); \
83 static int test_##name(void)
84
run_test_table(void)85 static inline int run_test_table(void) {
86 int r = EXIT_SUCCESS;
87
88 if (!__start_SYSTEMD_TEST_TABLE)
89 return r;
90
91 const TestFunc *t = ALIGN_TO_PTR(__start_SYSTEMD_TEST_TABLE, sizeof(TestFunc*));
92 while (t < __stop_SYSTEMD_TEST_TABLE) {
93
94 if (t->sd_booted && sd_booted() <= 0) {
95 log_info("/* systemd not booted, skipping %s */", t->name);
96 if (t->has_ret && r == EXIT_SUCCESS)
97 r = EXIT_TEST_SKIP;
98 } else {
99 log_info("/* %s */", t->name);
100
101 if (t->has_ret) {
102 int r2 = t->f.int_func();
103 if (r == EXIT_SUCCESS)
104 r = r2;
105 } else
106 t->f.void_func();
107 }
108
109 t = ALIGN_TO_PTR(t + 1, sizeof(TestFunc*));
110 }
111
112 return r;
113 }
114
115 #define DEFINE_TEST_MAIN_FULL(log_level, intro, outro) \
116 int main(int argc, char *argv[]) { \
117 int (*_intro)(void) = intro; \
118 int (*_outro)(void) = outro; \
119 int _r, _q; \
120 test_setup_logging(log_level); \
121 save_argc_argv(argc, argv); \
122 _r = _intro ? _intro() : EXIT_SUCCESS; \
123 if (_r == EXIT_SUCCESS) \
124 _r = run_test_table(); \
125 _q = _outro ? _outro() : EXIT_SUCCESS; \
126 static_destruct(); \
127 if (_r < 0) \
128 return EXIT_FAILURE; \
129 if (_r != EXIT_SUCCESS) \
130 return _r; \
131 if (_q < 0) \
132 return EXIT_FAILURE; \
133 return _q; \
134 }
135
136 #define DEFINE_TEST_MAIN_WITH_INTRO(log_level, intro) \
137 DEFINE_TEST_MAIN_FULL(log_level, intro, NULL)
138 #define DEFINE_TEST_MAIN(log_level) \
139 DEFINE_TEST_MAIN_FULL(log_level, NULL, NULL)
140