1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
11 #include "process-util.h"
12 #include "rlimit-util.h"
13 #include "signal-util.h"
14 #include "static-destruct.h"
17 static inline void log_set_assert_return_is_criticalp(bool *p
) {
18 log_set_assert_return_is_critical(*p
);
21 #define _SAVE_ASSERT_RETURN_IS_CRITICAL(b) \
22 _unused_ _cleanup_(log_set_assert_return_is_criticalp) bool b = \
23 log_get_assert_return_is_critical()
25 #define SAVE_ASSERT_RETURN_IS_CRITICAL \
26 _SAVE_ASSERT_RETURN_IS_CRITICAL(UNIQ_T(saved, UNIQ))
28 #define ASSERT_RETURN_IS_CRITICAL(b, expr) \
30 SAVE_ASSERT_RETURN_IS_CRITICAL; \
31 log_set_assert_return_is_critical(b); \
35 #define ASSERT_RETURN_EXPECTED(expr) ASSERT_RETURN_IS_CRITICAL(false, expr)
36 #define ASSERT_RETURN_EXPECTED_SE(expr) ASSERT_RETURN_EXPECTED(assert_se(expr));
38 static inline bool manager_errno_skip_test(int r
) {
45 ENOMEDIUM
/* cannot determine cgroup */
49 char* setup_fake_runtime_dir(void);
50 int enter_cgroup_subroot(char **ret_cgroup
);
51 int enter_cgroup_root(char **ret_cgroup
);
52 int get_testdata_dir(const char *suffix
, char **ret
);
53 const char* get_catalog_dir(void);
54 bool slow_tests_enabled(void);
55 void test_setup_logging(int level
);
57 #define log_tests_skipped(fmt, ...) \
59 log_notice("%s: " fmt ", skipping tests.", \
60 program_invocation_short_name, \
65 #define log_tests_skipped_errno(error, fmt, ...) \
67 log_notice_errno(error, \
68 "%s: " fmt ", skipping tests: %m", \
69 program_invocation_short_name, \
74 int write_tmpfile(char *pattern
, const char *contents
);
76 bool have_namespaces(void);
78 /* We use the small but non-trivial limit here */
79 #define CAN_MEMLOCK_SIZE (512 * 1024U)
80 bool can_memlock(void);
82 /* Define void* buffer and size_t length variables from a hex string. */
83 #define DEFINE_HEX_PTR(name, hex) \
84 _cleanup_free_ void *name = NULL; \
85 size_t name##_len = 0; \
86 assert_se(unhexmem_full(hex, strlen_ptr(hex), false, &name, &name##_len) >= 0);
88 #define TEST_REQ_RUNNING_SYSTEMD(x) \
89 if (sd_booted() > 0) { \
92 printf("systemd not booted, skipping '%s'\n", #x); \
95 /* Provide a convenient way to check if we're running in CI. */
96 const char *ci_environment(void);
98 typedef struct TestFunc
{
100 void (*void_func
)(void);
101 int (*int_func
)(void);
103 const char * const name
;
108 /* See static-destruct.h for an explanation of how this works. */
109 #define REGISTER_TEST(func, ...) \
110 _Pragma("GCC diagnostic ignored \"-Wattributes\"") \
111 _section_("SYSTEMD_TEST_TABLE") _alignptr_ _used_ _retain_ _variable_no_sanitize_address_ \
112 static const TestFunc UNIQ_T(static_test_table_entry, UNIQ) = { \
113 .f = (union f) &(func), \
114 .name = STRINGIFY(func), \
115 .has_ret = __builtin_types_compatible_p(typeof((union f){}.int_func), typeof(&(func))), \
119 extern const TestFunc _weak_ __start_SYSTEMD_TEST_TABLE
[];
120 extern const TestFunc _weak_ __stop_SYSTEMD_TEST_TABLE
[];
122 #define TEST(name, ...) \
123 static void test_##name(void); \
124 REGISTER_TEST(test_##name, ##__VA_ARGS__); \
125 static void test_##name(void)
127 #define TEST_RET(name, ...) \
128 static int test_##name(void); \
129 REGISTER_TEST(test_##name, ##__VA_ARGS__); \
130 static int test_##name(void)
132 #define TEST_LOG_FUNC() \
133 log_info("/* %s() */", __func__)
135 static inline int run_test_table(void) {
136 _cleanup_strv_free_
char **tests
= NULL
;
137 int r
= EXIT_SUCCESS
;
141 if (!__start_SYSTEMD_TEST_TABLE
)
144 e
= getenv("TESTFUNCS");
146 r
= strv_split_full(&tests
, e
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
148 return log_error_errno(r
, "Failed to parse $TESTFUNCS: %m");
151 for (const TestFunc
*t
= ALIGN_PTR(__start_SYSTEMD_TEST_TABLE
);
152 t
+ 1 <= __stop_SYSTEMD_TEST_TABLE
;
153 t
= ALIGN_PTR(t
+ 1)) {
155 if (tests
&& !strv_contains(tests
, t
->name
))
158 if (t
->sd_booted
&& sd_booted() <= 0) {
159 log_info("/* systemd not booted, skipping %s */", t
->name
);
160 if (t
->has_ret
&& r
== EXIT_SUCCESS
)
163 log_info("/* %s */", t
->name
);
166 int r2
= t
->f
.int_func();
167 if (r
== EXIT_SUCCESS
)
177 return log_error_errno(SYNTHETIC_ERRNO(ENXIO
), "No matching tests found.");
182 #define DEFINE_TEST_MAIN_FULL(log_level, intro, outro) \
183 int main(int argc, char *argv[]) { \
184 int (*_intro)(void) = intro; \
185 int (*_outro)(void) = outro; \
187 test_setup_logging(log_level); \
188 save_argc_argv(argc, argv); \
189 _r = _intro ? _intro() : EXIT_SUCCESS; \
190 if (_r == EXIT_SUCCESS) \
191 _r = run_test_table(); \
192 _q = _outro ? _outro() : EXIT_SUCCESS; \
195 return EXIT_FAILURE; \
196 if (_r != EXIT_SUCCESS) \
199 return EXIT_FAILURE; \
203 #define DEFINE_TEST_MAIN_WITH_INTRO(log_level, intro) \
204 DEFINE_TEST_MAIN_FULL(log_level, intro, NULL)
205 #define DEFINE_TEST_MAIN(log_level) \
206 DEFINE_TEST_MAIN_FULL(log_level, NULL, NULL)
208 #define ASSERT_OK(expr) \
210 typeof(expr) _result = (expr); \
212 log_error_errno(_result, "%s:%i: Assertion failed: %s: %m", \
213 PROJECT_FILE, __LINE__, #expr); \
218 #define ASSERT_TRUE(expr) \
221 log_error("%s:%i: Assertion failed: expected \"%s\" to be true", \
222 PROJECT_FILE, __LINE__, #expr); \
227 #define ASSERT_FALSE(expr) \
230 log_error("%s:%i: Assertion failed: expected \"%s\" to be false", \
231 PROJECT_FILE, __LINE__, #expr); \
236 #define ASSERT_NULL(expr) \
238 if ((expr) != NULL) { \
239 log_error("%s:%i: Assertion failed: expected \"%s\" to be NULL", \
240 PROJECT_FILE, __LINE__, #expr); \
245 #define ASSERT_NOT_NULL(expr) \
247 if ((expr) == NULL) { \
248 log_error("%s:%i: Assertion failed: expected \"%s\" to be not NULL", \
249 PROJECT_FILE, __LINE__, #expr); \
254 #define ASSERT_STREQ(expr1, expr2) \
256 const char *_expr1 = (expr1), *_expr2 = (expr2); \
257 if (!streq_ptr(_expr1, _expr2)) { \
258 log_error("%s:%i: Assertion failed: expected \"%s == %s\", but \"%s != %s\"", \
259 PROJECT_FILE, __LINE__, #expr1, #expr2, strnull(_expr1), strnull(_expr2)); \
264 /* DECIMAL_STR_FMT() uses _Generic which cannot be used in string concatenation so we have to format the
265 * input into strings first and then format those into the final assertion message. */
267 #define ASSERT_EQ(expr1, expr2) \
269 typeof(expr1) _expr1 = (expr1); \
270 typeof(expr2) _expr2 = (expr2); \
271 if (_expr1 != _expr2) { \
272 char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
273 char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
274 xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
275 xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
276 log_error("%s:%i: Assertion failed: expected \"%s == %s\", but \"%s != %s\"", \
277 PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
282 #define ASSERT_GE(expr1, expr2) \
284 typeof(expr1) _expr1 = (expr1); \
285 typeof(expr2) _expr2 = (expr2); \
286 if (_expr1 < _expr2) { \
287 char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
288 char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
289 xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
290 xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
291 log_error("%s:%i: Assertion failed: expected \"%s >= %s\", but \"%s < %s\"", \
292 PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
297 #define ASSERT_LE(expr1, expr2) \
299 typeof(expr1) _expr1 = (expr1); \
300 typeof(expr2) _expr2 = (expr2); \
301 if (_expr1 > _expr2) { \
302 char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
303 char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
304 xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
305 xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
306 log_error("%s:%i: Assertion failed: expected \"%s <= %s\", but \"%s > %s\"", \
307 PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
312 #define ASSERT_NE(expr1, expr2) \
314 typeof(expr1) _expr1 = (expr1); \
315 typeof(expr2) _expr2 = (expr2); \
316 if (_expr1 == _expr2) { \
317 char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
318 char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
319 xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
320 xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
321 log_error("%s:%i: Assertion failed: expected \"%s != %s\", but \"%s == %s\"", \
322 PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
327 #define ASSERT_GT(expr1, expr2) \
329 typeof(expr1) _expr1 = (expr1); \
330 typeof(expr2) _expr2 = (expr2); \
331 if (!(_expr1 > _expr2)) { \
332 char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
333 char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
334 xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
335 xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
336 log_error("%s:%i: Assertion failed: expected \"%s > %s\", but \"%s <= %s\"", \
337 PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
342 #define ASSERT_LT(expr1, expr2) \
344 typeof(expr1) _expr1 = (expr1); \
345 typeof(expr2) _expr2 = (expr2); \
346 if (!(_expr1 < _expr2)) { \
347 char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
348 char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
349 xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
350 xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
351 log_error("%s:%i: Assertion failed: expected \"%s < %s\", but \"%s >= %s\"", \
352 PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
357 #define ASSERT_SIGNAL(expr, signal) \
359 ASSERT_TRUE(SIGNAL_VALID(signal)); \
360 siginfo_t _siginfo = {}; \
364 /* Speed things up by never even attempting to generate a coredump */ \
365 (void) prctl(PR_SET_DUMPABLE, 0); \
366 /* But still set an rlimit just in case */ \
367 (void) setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(0)); \
369 _exit(EXIT_SUCCESS); \
371 (void) wait_for_terminate(_pid, &_siginfo); \
372 if (_siginfo.si_status != signal) { \
373 log_error("%s:%i: Assertion failed: \"%s\" died with signal %s, but %s was expected", \
374 PROJECT_FILE, __LINE__, #expr, signal_to_string(_siginfo.si_status), \
375 signal_to_string(signal)); \