]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-log.c
mkosi: Use initrd as exitrd
[thirdparty/systemd.git] / src / test / test-log.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
877d54e9 2
f97b34a6 3#include "format-util.h"
bd1ae178 4#include "iovec-util.h"
ea1f3814 5#include "iovec-wrapper.h"
877d54e9 6#include "log.h"
a4bff6ef 7#include "log-context.h"
dccca82b 8#include "process-util.h"
a0b15b41 9#include "string-util.h"
7c7a9138 10#include "strv.h"
965040d8 11#include "tests.h"
877d54e9 12
f8e6f4aa
ZJS
13#define X10(x) x x x x x x x x x x
14#define X100(x) X10(X10(x))
15#define X1000(x) X100(X10(x))
877d54e9 16
c1792c20
YW
17TEST(synthetic_errno) {
18 ASSERT_TRUE(IS_SYNTHETIC_ERRNO(SYNTHETIC_ERRNO(EINVAL)));
19 ASSERT_TRUE(IS_SYNTHETIC_ERRNO(SYNTHETIC_ERRNO(-EINVAL)));
20 assert_cc(!IS_SYNTHETIC_ERRNO(EINVAL));
21 assert_cc(!IS_SYNTHETIC_ERRNO(-EINVAL));
22 ASSERT_TRUE(IS_SYNTHETIC_ERRNO(SYNTHETIC_ERRNO(0)));
23 assert_cc(!IS_SYNTHETIC_ERRNO(0));
24 ASSERT_EQ(ERRNO_VALUE(EINVAL), EINVAL);
25 ASSERT_EQ(ERRNO_VALUE(SYNTHETIC_ERRNO(-EINVAL)), EINVAL);
26
27 ASSERT_ERROR(log_info_errno(SYNTHETIC_ERRNO(EUCLEAN), "foo"), EUCLEAN);
28}
29
8161f608
YW
30static int fail_with_EINVAL(void) {
31 assert_return(false, -EINVAL);
32 return 0;
33}
34
c1792c20 35TEST(assert_return_is_critical) {
8161f608
YW
36 SAVE_ASSERT_RETURN_IS_CRITICAL;
37
38 log_set_assert_return_is_critical(false);
c1792c20 39 ASSERT_ERROR(fail_with_EINVAL(), EINVAL);
8161f608
YW
40
41 log_set_assert_return_is_critical(true);
c1792c20
YW
42 ASSERT_RETURN_IS_CRITICAL(false, ASSERT_ERROR(fail_with_EINVAL(), EINVAL));
43 ASSERT_TRUE(log_get_assert_return_is_critical());
44 ASSERT_RETURN_EXPECTED(ASSERT_ERROR(fail_with_EINVAL(), EINVAL));
45 ASSERT_TRUE(log_get_assert_return_is_critical());
8161f608 46 ASSERT_RETURN_EXPECTED_SE(fail_with_EINVAL() == -EINVAL);
c1792c20 47 ASSERT_TRUE(log_get_assert_return_is_critical());
8161f608
YW
48}
49
c1792c20 50TEST(file) {
a0b15b41
ZJS
51 log_info("__FILE__: %s", __FILE__);
52 log_info("RELATIVE_SOURCE_PATH: %s", RELATIVE_SOURCE_PATH);
53 log_info("PROJECT_FILE: %s", PROJECT_FILE);
54
c1792c20 55 ASSERT_NOT_NULL(startswith(__FILE__, RELATIVE_SOURCE_PATH "/"));
a0b15b41
ZJS
56}
57
acd33c5d
YW
58static void test_log_once_impl(void) {
59 log_once(LOG_INFO, "This should be logged in LOG_INFO at first, then in LOG_DEBUG later.");
60 log_once(LOG_DEBUG, "This should be logged only once in LOG_DEBUG.");
61 ASSERT_ERROR(log_once_errno(LOG_INFO, SYNTHETIC_ERRNO(ENOANO),
62 "This should be logged with errno in LOG_INFO at first, then in LOG_DEBUG later: %m"),
63 ENOANO);
64 ASSERT_ERROR(log_once_errno(LOG_DEBUG, SYNTHETIC_ERRNO(EBADMSG),
65 "This should be logged only once with errno in LOG_DEBUG: %m"),
66 EBADMSG);
67}
68
c1792c20 69TEST(log_once) {
acd33c5d
YW
70 for (unsigned i = 0; i < 4; i++)
71 test_log_once_impl();
72}
73
f1044431
YW
74_sentinel_
75static void test_log_format_iovec_sentinel(
76 char * const *expected,
77 const char *format,
78 ...) {
79
80 size_t iovec_len = 20, n = 0;
81 struct iovec *iovec = newa(struct iovec, iovec_len);
82 va_list ap;
83
84 log_debug("/* %s(%s) */", __func__, strnull(format));
85
86 char **v = STRV_MAKE("SYSLOG_FACILITY=3",
87 "SYSLOG_IDENTIFIER=systemd-journald",
88 "_TRANSPORT=driver",
89 "PRIORITY=6");
90 size_t m = strv_length(v);
91
92 STRV_FOREACH(s, v)
93 iovec[n++] = IOVEC_MAKE_STRING(*s);
94
95 ASSERT_EQ(n, m);
96
97 va_start(ap, format);
98 DISABLE_WARNING_FORMAT_NONLITERAL;
93378148 99 ASSERT_OK(log_format_iovec(iovec, iovec_len, &n, /* newline_separator= */ false, ENOANO, format, ap));
f1044431
YW
100 REENABLE_WARNING;
101 va_end(ap);
102
103 ASSERT_EQ(n, m + strv_length(expected));
104
105 for (size_t i = 0; i < n; i++)
106 if (i < m)
107 ASSERT_EQ(iovec_memcmp(&iovec[i], &IOVEC_MAKE_STRING(v[i])), 0);
108 else {
109 ASSERT_EQ(iovec_memcmp(&iovec[i], &IOVEC_MAKE_STRING(expected[i - m])), 0);
110 free(iovec[i].iov_base);
111 }
112
113 n = m;
114
115 va_start(ap, format);
116 DISABLE_WARNING_FORMAT_NONLITERAL;
93378148 117 ASSERT_OK(log_format_iovec(iovec, iovec_len, &n, /* newline_separator= */ true, ENOANO, format, ap));
f1044431
YW
118 REENABLE_WARNING;
119 va_end(ap);
120
121 ASSERT_EQ(n, m + strv_length(expected) * 2);
122
123 for (size_t i = 0; i < n; i++)
124 if (i < m)
125 ASSERT_EQ(iovec_memcmp(&iovec[i], &IOVEC_MAKE_STRING(v[i])), 0);
126 else if ((i - m) % 2 == 0) {
127 ASSERT_EQ(iovec_memcmp(&iovec[i], &IOVEC_MAKE_STRING(expected[(i - m) / 2])), 0);
128 free(iovec[i].iov_base);
129 } else
130 ASSERT_EQ(iovec_memcmp(&iovec[i], &IOVEC_MAKE_STRING("\n")), 0);
131}
132
133#define test_log_format_iovec_one(...) \
134 test_log_format_iovec_sentinel(__VA_ARGS__, NULL)
135
136TEST(log_format_iovec) {
137 test_log_format_iovec_one(NULL, NULL);
138 test_log_format_iovec_one(STRV_MAKE("MESSAGE=hoge"),
139 LOG_MESSAGE("hoge"));
140 test_log_format_iovec_one(STRV_MAKE("MESSAGE=hoge: 10"),
141 LOG_MESSAGE("hoge: %i", 10));
142 test_log_format_iovec_one(STRV_MAKE("MESSAGE=hoge: 10-a", "HOGEHOGE=100-string", "FOOFOO=4-3"),
143 LOG_MESSAGE("hoge: %i-%c", 10, 'a'),
144 LOG_ITEM("HOGEHOGE=%zu-%s", (size_t) 100, "string"),
145 LOG_ITEM("FOOFOO=%hu-%llu", (unsigned short) 4, (long long unsigned) 3));
146}
147
52d86690 148static void test_log_struct(void) {
877d54e9 149 log_struct(LOG_INFO,
52d86690 150 "MESSAGE=Waldo PID="PID_FMT" (no errno)", getpid_cached(),
a1230ff9 151 "SERVICE=piepapo");
877d54e9 152
3cf6a3a3 153 /* The same as above, just using LOG_MESSAGE() and LOG_ITEM(), which is generally recommended */
92663a5e
ZJS
154 log_struct(LOG_INFO,
155 LOG_MESSAGE("Waldo PID="PID_FMT" (no errno)", getpid_cached()),
3cf6a3a3 156 LOG_ITEM("SERVICE=piepapo"));
52d86690 157
92663a5e
ZJS
158 log_struct_errno(LOG_INFO, EILSEQ,
159 LOG_MESSAGE("Waldo PID="PID_FMT": %m (normal)", getpid_cached()),
3cf6a3a3 160 LOG_ITEM("SERVICE=piepapo"));
92663a5e 161
52d86690 162 log_struct_errno(LOG_INFO, SYNTHETIC_ERRNO(EILSEQ),
92663a5e 163 LOG_MESSAGE("Waldo PID="PID_FMT": %m (synthetic)", getpid_cached()),
3cf6a3a3 164 LOG_ITEM("SERVICE=piepapo"));
877d54e9 165
963ddb91 166 log_struct(LOG_INFO,
92663a5e 167 LOG_MESSAGE("Foobar PID="PID_FMT, getpid_cached()),
3cf6a3a3 168 LOG_ITEM("FORMAT_STR_TEST=1=%i A=%c 2=%hi 3=%li 4=%lli 1=%p foo=%s 2.5=%g 3.5=%g 4.5=%Lg",
9ec7d7ae 169 (int) 1, 'A', (short) 2, (long) 3, (long long) 4, (void*) 1, "foo", (float) 2.5f, (double) 3.5, (long double) 4.5),
3cf6a3a3 170 LOG_ITEM("SUFFIX=GOT IT"));
f8e6f4aa
ZJS
171}
172
173static void test_long_lines(void) {
174 log_object_internal(LOG_NOTICE,
175 EUCLEAN,
176 X1000("abcd_") ".txt",
177 1000000,
178 X1000("fff") "unc",
179 "OBJECT=",
180 X1000("obj_") "ect",
181 "EXTRA=",
182 X1000("ext_") "tra",
183 "asdfasdf %s asdfasdfa", "foobar");
184}
185
59c1546b 186static void test_log_syntax(void) {
c1792c20
YW
187 ASSERT_ERROR(log_syntax("unit", LOG_ERR, "filename", 10, EINVAL, "EINVAL: %s: %m", "hogehoge"), EINVAL);
188 ASSERT_ERROR(log_syntax("unit", LOG_ERR, "filename", 10, -ENOENT, "ENOENT: %s: %m", "hogehoge"), ENOENT);
189 ASSERT_ERROR(log_syntax("unit", LOG_ERR, "filename", 10, SYNTHETIC_ERRNO(ENOTTY), "ENOTTY: %s: %m", "hogehoge"), ENOTTY);
59c1546b
YW
190}
191
7c7a9138
DDM
192static void test_log_context(void) {
193 {
194 char **strv = STRV_MAKE("FIRST=abc", "SECOND=qrs");
195
196 LOG_CONTEXT_PUSH("THIRD=pfs");
197 LOG_CONTEXT_PUSH("FOURTH=def");
198 LOG_CONTEXT_PUSH_STRV(strv);
199 LOG_CONTEXT_PUSH_STRV(strv);
200
88335453
DDM
201 /* Test that the log context was set up correctly. The strv we pushed twice should only
202 * result in one log context which is reused. */
c1792c20
YW
203 ASSERT_EQ(log_context_num_contexts(), 3U);
204 ASSERT_EQ(log_context_num_fields(), 4U);
7c7a9138
DDM
205
206 /* Test that everything still works with modifications to the log context. */
207 test_log_struct();
208 test_long_lines();
209 test_log_syntax();
210
211 {
212 LOG_CONTEXT_PUSH("FIFTH=123");
213 LOG_CONTEXT_PUSH_STRV(strv);
214
215 /* Check that our nested fields got added correctly. */
c1792c20
YW
216 ASSERT_EQ(log_context_num_contexts(), 4U);
217 ASSERT_EQ(log_context_num_fields(), 5U);
7c7a9138
DDM
218
219 /* Test that everything still works in a nested block. */
220 test_log_struct();
221 test_long_lines();
222 test_log_syntax();
223 }
224
225 /* Check that only the fields from the nested block got removed. */
c1792c20
YW
226 ASSERT_EQ(log_context_num_contexts(), 3U);
227 ASSERT_EQ(log_context_num_fields(), 4U);
7c7a9138
DDM
228 }
229
c1792c20
YW
230 ASSERT_EQ(log_context_num_contexts(), 0U);
231 ASSERT_EQ(log_context_num_fields(), 0U);
7c7a9138
DDM
232
233 {
88335453 234 _cleanup_(log_context_unrefp) LogContext *ctx = NULL;
7c7a9138
DDM
235
236 char **strv = STRV_MAKE("SIXTH=ijn", "SEVENTH=PRP");
93378148 237 ASSERT_NOT_NULL(ctx = log_context_new_strv(strv, /* owned= */ false));
7c7a9138 238
c1792c20
YW
239 ASSERT_EQ(log_context_num_contexts(), 1U);
240 ASSERT_EQ(log_context_num_fields(), 2U);
7c7a9138
DDM
241
242 /* Test that everything still works with a manually configured log context. */
243 test_log_struct();
244 test_long_lines();
245 test_log_syntax();
246 }
247
248 {
249 char **strv = NULL;
250
c1792c20 251 ASSERT_NOT_NULL(strv = strv_new("ABC", "DEF"));
7c7a9138
DDM
252 LOG_CONTEXT_CONSUME_STRV(strv);
253
c1792c20
YW
254 ASSERT_EQ(log_context_num_contexts(), 1U);
255 ASSERT_EQ(log_context_num_fields(), 2U);
7c7a9138
DDM
256 }
257
2461943b
LB
258 {
259 /* Test that everything still works with a mixed strv and iov. */
260 struct iovec iov[] = {
261 IOVEC_MAKE_STRING("ABC=def"),
262 IOVEC_MAKE_STRING("GHI=jkl"),
263 };
c1792c20
YW
264 _cleanup_free_ struct iovec_wrapper *iovw = NULL;
265 ASSERT_NOT_NULL(iovw = iovw_new());
266 ASSERT_OK(iovw_consume(iovw, strdup("MNO=pqr"), STRLEN("MNO=pqr") + 1));
2461943b 267
88335453 268 LOG_CONTEXT_PUSH_IOV(iov, ELEMENTSOF(iov));
2461943b
LB
269 LOG_CONTEXT_PUSH_IOV(iov, ELEMENTSOF(iov));
270 LOG_CONTEXT_CONSUME_IOV(iovw->iovec, iovw->count);
271 LOG_CONTEXT_PUSH("STU=vwx");
272
c1792c20
YW
273 ASSERT_EQ(log_context_num_contexts(), 3U);
274 ASSERT_EQ(log_context_num_fields(), 4U);
2461943b
LB
275
276 test_log_struct();
277 test_long_lines();
278 test_log_syntax();
279 }
280
81b3565e
DDM
281 {
282 LOG_CONTEXT_PUSH_KEY_VALUE("ABC=", "QED");
283 LOG_CONTEXT_PUSH_KEY_VALUE("ABC=", "QED");
c1792c20
YW
284 ASSERT_EQ(log_context_num_contexts(), 1U);
285 ASSERT_EQ(log_context_num_fields(), 1U);
81b3565e
DDM
286
287 test_log_struct();
288 test_long_lines();
289 test_log_syntax();
290 }
291
c1792c20
YW
292 ASSERT_EQ(log_context_num_contexts(), 0U);
293 ASSERT_EQ(log_context_num_fields(), 0U);
7c7a9138
DDM
294}
295
ee2975a9
DDM
296static void test_log_prefix(void) {
297 {
298 LOG_SET_PREFIX("ABC");
299
300 test_log_struct();
301 test_long_lines();
302 test_log_syntax();
303
304 {
305 LOG_SET_PREFIX("QED");
306
307 test_log_struct();
308 test_long_lines();
309 test_log_syntax();
310 }
311
312 test_log_struct();
313 test_long_lines();
314 test_log_syntax();
315 }
316
317 test_log_struct();
318 test_long_lines();
319 test_log_syntax();
320}
321
c1792c20 322TEST(log_target) {
169d980b 323 for (int target = 0; target < _LOG_TARGET_MAX; target++) {
f8e6f4aa
ZJS
324 log_set_target(target);
325 log_open();
326
52d86690 327 test_log_struct();
f8e6f4aa 328 test_long_lines();
59c1546b 329 test_log_syntax();
7c7a9138 330 test_log_context();
ee2975a9 331 test_log_prefix();
f8e6f4aa 332 }
877d54e9 333}
c1792c20
YW
334
335DEFINE_TEST_MAIN(LOG_DEBUG);