]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
d2120590 LP |
2 | #pragma once |
3 | ||
ca7a9afc ZJS |
4 | #include <stdbool.h> |
5 | ||
48e98ba5 ZJS |
6 | #include "sd-daemon.h" |
7 | ||
ee617a4e | 8 | #include "argv-util.h" |
5eecb103 | 9 | #include "macro.h" |
99839c7e | 10 | #include "static-destruct.h" |
f1a83e41 | 11 | #include "strv.h" |
5eecb103 | 12 | |
8161f608 YW |
13 | static inline void log_set_assert_return_is_criticalp(bool *p) { |
14 | log_set_assert_return_is_critical(*p); | |
15 | } | |
16 | ||
17 | #define _SAVE_ASSERT_RETURN_IS_CRITICAL(b) \ | |
18 | _unused_ _cleanup_(log_set_assert_return_is_criticalp) bool b = \ | |
19 | log_get_assert_return_is_critical() | |
20 | ||
21 | #define SAVE_ASSERT_RETURN_IS_CRITICAL \ | |
22 | _SAVE_ASSERT_RETURN_IS_CRITICAL(UNIQ_T(saved, UNIQ)) | |
23 | ||
24 | #define ASSERT_RETURN_IS_CRITICAL(b, expr) \ | |
25 | ({ \ | |
26 | SAVE_ASSERT_RETURN_IS_CRITICAL; \ | |
27 | log_set_assert_return_is_critical(b); \ | |
28 | expr; \ | |
29 | }) | |
30 | ||
31 | #define ASSERT_RETURN_EXPECTED(expr) ASSERT_RETURN_IS_CRITICAL(false, expr) | |
32 | #define ASSERT_RETURN_EXPECTED_SE(expr) ASSERT_RETURN_EXPECTED(assert_se(expr)); | |
33 | ||
5eecb103 ZJS |
34 | static inline bool manager_errno_skip_test(int r) { |
35 | return IN_SET(abs(r), | |
36 | EPERM, | |
37 | EACCES, | |
38 | EADDRINUSE, | |
39 | EHOSTDOWN, | |
40 | ENOENT, | |
41 | ENOMEDIUM /* cannot determine cgroup */ | |
42 | ); | |
43 | } | |
44 | ||
d2120590 | 45 | char* setup_fake_runtime_dir(void); |
64ad9e08 | 46 | int enter_cgroup_subroot(char **ret_cgroup); |
61ff7397 | 47 | int enter_cgroup_root(char **ret_cgroup); |
7b432953 | 48 | int get_testdata_dir(const char *suffix, char **ret); |
49cdae63 | 49 | const char* get_catalog_dir(void); |
0cf29baa | 50 | bool slow_tests_enabled(void); |
6d7c4033 | 51 | void test_setup_logging(int level); |
678fbf7e YW |
52 | |
53 | #define log_tests_skipped(fmt, ...) \ | |
54 | ({ \ | |
55 | log_notice("%s: " fmt ", skipping tests.", \ | |
56 | program_invocation_short_name, \ | |
57 | ##__VA_ARGS__); \ | |
58 | EXIT_TEST_SKIP; \ | |
59 | }) | |
60 | ||
61 | #define log_tests_skipped_errno(error, fmt, ...) \ | |
62 | ({ \ | |
63 | log_notice_errno(error, \ | |
64 | "%s: " fmt ", skipping tests: %m", \ | |
65 | program_invocation_short_name, \ | |
66 | ##__VA_ARGS__); \ | |
67 | EXIT_TEST_SKIP; \ | |
68 | }) | |
a4bc3c1d | 69 | |
367c47c8 ZJS |
70 | int write_tmpfile(char *pattern, const char *contents); |
71 | ||
a4bc3c1d | 72 | bool have_namespaces(void); |
77abd029 ZJS |
73 | |
74 | /* We use the small but non-trivial limit here */ | |
75 | #define CAN_MEMLOCK_SIZE (512 * 1024U) | |
76 | bool can_memlock(void); | |
48e98ba5 | 77 | |
0fdcfa78 DS |
78 | /* Define void* buffer and size_t length variables from a hex string. */ |
79 | #define DEFINE_HEX_PTR(name, hex) \ | |
80 | _cleanup_free_ void *name = NULL; \ | |
81 | size_t name##_len = 0; \ | |
bdd2036e | 82 | assert_se(unhexmem_full(hex, strlen_ptr(hex), false, &name, &name##_len) >= 0); |
0fdcfa78 | 83 | |
48e98ba5 ZJS |
84 | #define TEST_REQ_RUNNING_SYSTEMD(x) \ |
85 | if (sd_booted() > 0) { \ | |
86 | x; \ | |
87 | } else { \ | |
0578dfe3 | 88 | printf("systemd not booted, skipping '%s'\n", #x); \ |
48e98ba5 | 89 | } |
4eb0c875 ZJS |
90 | |
91 | /* Provide a convenient way to check if we're running in CI. */ | |
92 | const char *ci_environment(void); | |
9cc61546 JJ |
93 | |
94 | typedef struct TestFunc { | |
4c0acc07 JJ |
95 | union f { |
96 | void (*void_func)(void); | |
97 | int (*int_func)(void); | |
98 | } f; | |
99 | const char * const name; | |
0578dfe3 JJ |
100 | bool has_ret:1; |
101 | bool sd_booted:1; | |
9cc61546 JJ |
102 | } TestFunc; |
103 | ||
104 | /* See static-destruct.h for an explanation of how this works. */ | |
0578dfe3 | 105 | #define REGISTER_TEST(func, ...) \ |
a3aff1c4 JJ |
106 | _Pragma("GCC diagnostic ignored \"-Wattributes\"") \ |
107 | _section_("SYSTEMD_TEST_TABLE") _alignptr_ _used_ _retain_ _variable_no_sanitize_address_ \ | |
4c0acc07 JJ |
108 | static const TestFunc UNIQ_T(static_test_table_entry, UNIQ) = { \ |
109 | .f = (union f) &(func), \ | |
110 | .name = STRINGIFY(func), \ | |
111 | .has_ret = __builtin_types_compatible_p(typeof((union f){}.int_func), typeof(&(func))), \ | |
0578dfe3 | 112 | ##__VA_ARGS__ \ |
9cc61546 JJ |
113 | } |
114 | ||
115 | extern const TestFunc _weak_ __start_SYSTEMD_TEST_TABLE[]; | |
116 | extern const TestFunc _weak_ __stop_SYSTEMD_TEST_TABLE[]; | |
117 | ||
0578dfe3 JJ |
118 | #define TEST(name, ...) \ |
119 | static void test_##name(void); \ | |
120 | REGISTER_TEST(test_##name, ##__VA_ARGS__); \ | |
9cc61546 JJ |
121 | static void test_##name(void) |
122 | ||
0578dfe3 JJ |
123 | #define TEST_RET(name, ...) \ |
124 | static int test_##name(void); \ | |
125 | REGISTER_TEST(test_##name, ##__VA_ARGS__); \ | |
4c0acc07 JJ |
126 | static int test_##name(void) |
127 | ||
47a7a4d4 LP |
128 | #define TEST_LOG_FUNC() \ |
129 | log_info("/* %s() */", __func__) | |
130 | ||
4c0acc07 | 131 | static inline int run_test_table(void) { |
f1a83e41 | 132 | _cleanup_strv_free_ char **tests = NULL; |
4c0acc07 | 133 | int r = EXIT_SUCCESS; |
f1a83e41 LP |
134 | bool ran = false; |
135 | const char *e; | |
4c0acc07 | 136 | |
9cc61546 | 137 | if (!__start_SYSTEMD_TEST_TABLE) |
4c0acc07 | 138 | return r; |
9cc61546 | 139 | |
f1a83e41 LP |
140 | e = getenv("TESTFUNCS"); |
141 | if (e) { | |
142 | r = strv_split_full(&tests, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS); | |
143 | if (r < 0) | |
144 | return log_error_errno(r, "Failed to parse $TESTFUNCS: %m"); | |
145 | } | |
146 | ||
147 | for (const TestFunc *t = ALIGN_PTR(__start_SYSTEMD_TEST_TABLE); | |
148 | t + 1 <= __stop_SYSTEMD_TEST_TABLE; | |
149 | t = ALIGN_PTR(t + 1)) { | |
150 | ||
151 | if (tests && !strv_contains(tests, t->name)) | |
152 | continue; | |
0578dfe3 JJ |
153 | |
154 | if (t->sd_booted && sd_booted() <= 0) { | |
155 | log_info("/* systemd not booted, skipping %s */", t->name); | |
156 | if (t->has_ret && r == EXIT_SUCCESS) | |
157 | r = EXIT_TEST_SKIP; | |
158 | } else { | |
159 | log_info("/* %s */", t->name); | |
160 | ||
161 | if (t->has_ret) { | |
162 | int r2 = t->f.int_func(); | |
163 | if (r == EXIT_SUCCESS) | |
164 | r = r2; | |
165 | } else | |
166 | t->f.void_func(); | |
167 | } | |
4c0acc07 | 168 | |
f1a83e41 | 169 | ran = true; |
9cc61546 | 170 | } |
4c0acc07 | 171 | |
f1a83e41 LP |
172 | if (!ran) |
173 | return log_error_errno(SYNTHETIC_ERRNO(ENXIO), "No matching tests found."); | |
174 | ||
4c0acc07 | 175 | return r; |
9cc61546 JJ |
176 | } |
177 | ||
e85fdacc YW |
178 | #define DEFINE_TEST_MAIN_FULL(log_level, intro, outro) \ |
179 | int main(int argc, char *argv[]) { \ | |
180 | int (*_intro)(void) = intro; \ | |
181 | int (*_outro)(void) = outro; \ | |
182 | int _r, _q; \ | |
183 | test_setup_logging(log_level); \ | |
184 | save_argc_argv(argc, argv); \ | |
185 | _r = _intro ? _intro() : EXIT_SUCCESS; \ | |
186 | if (_r == EXIT_SUCCESS) \ | |
187 | _r = run_test_table(); \ | |
188 | _q = _outro ? _outro() : EXIT_SUCCESS; \ | |
189 | static_destruct(); \ | |
190 | if (_r < 0) \ | |
191 | return EXIT_FAILURE; \ | |
192 | if (_r != EXIT_SUCCESS) \ | |
193 | return _r; \ | |
194 | if (_q < 0) \ | |
195 | return EXIT_FAILURE; \ | |
196 | return _q; \ | |
9cc61546 JJ |
197 | } |
198 | ||
e85fdacc YW |
199 | #define DEFINE_TEST_MAIN_WITH_INTRO(log_level, intro) \ |
200 | DEFINE_TEST_MAIN_FULL(log_level, intro, NULL) | |
201 | #define DEFINE_TEST_MAIN(log_level) \ | |
202 | DEFINE_TEST_MAIN_FULL(log_level, NULL, NULL) |