1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "format-util.h"
4 #include "iovec-util.h"
5 #include "iovec-wrapper.h"
7 #include "log-context.h"
8 #include "process-util.h"
9 #include "string-util.h"
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))
17 TEST(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
);
27 ASSERT_ERROR(log_info_errno(SYNTHETIC_ERRNO(EUCLEAN
), "foo"), EUCLEAN
);
30 static int fail_with_EINVAL(void) {
31 assert_return(false, -EINVAL
);
35 TEST(assert_return_is_critical
) {
36 SAVE_ASSERT_RETURN_IS_CRITICAL
;
38 log_set_assert_return_is_critical(false);
39 ASSERT_ERROR(fail_with_EINVAL(), EINVAL
);
41 log_set_assert_return_is_critical(true);
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());
46 ASSERT_RETURN_EXPECTED_SE(fail_with_EINVAL() == -EINVAL
);
47 ASSERT_TRUE(log_get_assert_return_is_critical());
51 log_info("__FILE__: %s", __FILE__
);
52 log_info("RELATIVE_SOURCE_PATH: %s", RELATIVE_SOURCE_PATH
);
53 log_info("PROJECT_FILE: %s", PROJECT_FILE
);
55 ASSERT_NOT_NULL(startswith(__FILE__
, RELATIVE_SOURCE_PATH
"/"));
58 static 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"),
64 ASSERT_ERROR(log_once_errno(LOG_DEBUG
, SYNTHETIC_ERRNO(EBADMSG
),
65 "This should be logged only once with errno in LOG_DEBUG: %m"),
70 for (unsigned i
= 0; i
< 4; i
++)
75 static void test_log_format_iovec_sentinel(
76 char * const *expected
,
80 size_t iovec_len
= 20, n
= 0;
81 struct iovec
*iovec
= newa(struct iovec
, iovec_len
);
84 log_debug("/* %s(%s) */", __func__
, strnull(format
));
86 char **v
= STRV_MAKE("SYSLOG_FACILITY=3",
87 "SYSLOG_IDENTIFIER=systemd-journald",
90 size_t m
= strv_length(v
);
93 iovec
[n
++] = IOVEC_MAKE_STRING(*s
);
98 DISABLE_WARNING_FORMAT_NONLITERAL
;
99 ASSERT_OK(log_format_iovec(iovec
, iovec_len
, &n
, /* newline_separator= */ false, ENOANO
, format
, ap
));
103 ASSERT_EQ(n
, m
+ strv_length(expected
));
105 for (size_t i
= 0; i
< n
; i
++)
107 ASSERT_EQ(iovec_memcmp(&iovec
[i
], &IOVEC_MAKE_STRING(v
[i
])), 0);
109 ASSERT_EQ(iovec_memcmp(&iovec
[i
], &IOVEC_MAKE_STRING(expected
[i
- m
])), 0);
110 free(iovec
[i
].iov_base
);
115 va_start(ap
, format
);
116 DISABLE_WARNING_FORMAT_NONLITERAL
;
117 ASSERT_OK(log_format_iovec(iovec
, iovec_len
, &n
, /* newline_separator= */ true, ENOANO
, format
, ap
));
121 ASSERT_EQ(n
, m
+ strv_length(expected
) * 2);
123 for (size_t i
= 0; i
< n
; i
++)
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
);
130 ASSERT_EQ(iovec_memcmp(&iovec
[i
], &IOVEC_MAKE_STRING("\n")), 0);
133 #define test_log_format_iovec_one(...) \
134 test_log_format_iovec_sentinel(__VA_ARGS__, NULL)
136 TEST(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));
148 static void test_log_struct(void) {
150 "MESSAGE=Waldo PID="PID_FMT
" (no errno)", getpid_cached(),
153 /* The same as above, just using LOG_MESSAGE() and LOG_ITEM(), which is generally recommended */
155 LOG_MESSAGE("Waldo PID="PID_FMT
" (no errno)", getpid_cached()),
156 LOG_ITEM("SERVICE=piepapo"));
158 log_struct_errno(LOG_INFO
, EILSEQ
,
159 LOG_MESSAGE("Waldo PID="PID_FMT
": %m (normal)", getpid_cached()),
160 LOG_ITEM("SERVICE=piepapo"));
162 log_struct_errno(LOG_INFO
, SYNTHETIC_ERRNO(EILSEQ
),
163 LOG_MESSAGE("Waldo PID="PID_FMT
": %m (synthetic)", getpid_cached()),
164 LOG_ITEM("SERVICE=piepapo"));
167 LOG_MESSAGE("Foobar PID="PID_FMT
, getpid_cached()),
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",
169 (int) 1, 'A', (short) 2, (long) 3, (long long) 4, (void*) 1, "foo", (float) 2.5f
, (double) 3.5, (long double) 4.5),
170 LOG_ITEM("SUFFIX=GOT IT"));
173 static void test_long_lines(void) {
174 log_object_internal(LOG_NOTICE
,
176 X1000("abcd_") ".txt",
183 "asdfasdf %s asdfasdfa", "foobar");
186 static void test_log_syntax(void) {
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
);
192 static void test_log_context(void) {
194 char **strv
= STRV_MAKE("FIRST=abc", "SECOND=qrs");
196 LOG_CONTEXT_PUSH("THIRD=pfs");
197 LOG_CONTEXT_PUSH("FOURTH=def");
198 LOG_CONTEXT_PUSH_STRV(strv
);
199 LOG_CONTEXT_PUSH_STRV(strv
);
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. */
203 ASSERT_EQ(log_context_num_contexts(), 3U);
204 ASSERT_EQ(log_context_num_fields(), 4U);
206 /* Test that everything still works with modifications to the log context. */
212 LOG_CONTEXT_PUSH("FIFTH=123");
213 LOG_CONTEXT_PUSH_STRV(strv
);
215 /* Check that our nested fields got added correctly. */
216 ASSERT_EQ(log_context_num_contexts(), 4U);
217 ASSERT_EQ(log_context_num_fields(), 5U);
219 /* Test that everything still works in a nested block. */
225 /* Check that only the fields from the nested block got removed. */
226 ASSERT_EQ(log_context_num_contexts(), 3U);
227 ASSERT_EQ(log_context_num_fields(), 4U);
230 ASSERT_EQ(log_context_num_contexts(), 0U);
231 ASSERT_EQ(log_context_num_fields(), 0U);
234 _cleanup_(log_context_unrefp
) LogContext
*ctx
= NULL
;
236 char **strv
= STRV_MAKE("SIXTH=ijn", "SEVENTH=PRP");
237 ASSERT_NOT_NULL(ctx
= log_context_new_strv(strv
, /* owned= */ false));
239 ASSERT_EQ(log_context_num_contexts(), 1U);
240 ASSERT_EQ(log_context_num_fields(), 2U);
242 /* Test that everything still works with a manually configured log context. */
251 ASSERT_NOT_NULL(strv
= strv_new("ABC", "DEF"));
252 LOG_CONTEXT_CONSUME_STRV(strv
);
254 ASSERT_EQ(log_context_num_contexts(), 1U);
255 ASSERT_EQ(log_context_num_fields(), 2U);
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"),
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));
268 LOG_CONTEXT_PUSH_IOV(iov
, ELEMENTSOF(iov
));
269 LOG_CONTEXT_PUSH_IOV(iov
, ELEMENTSOF(iov
));
270 LOG_CONTEXT_CONSUME_IOV(iovw
->iovec
, iovw
->count
);
271 LOG_CONTEXT_PUSH("STU=vwx");
273 ASSERT_EQ(log_context_num_contexts(), 3U);
274 ASSERT_EQ(log_context_num_fields(), 4U);
282 LOG_CONTEXT_PUSH_KEY_VALUE("ABC=", "QED");
283 LOG_CONTEXT_PUSH_KEY_VALUE("ABC=", "QED");
284 ASSERT_EQ(log_context_num_contexts(), 1U);
285 ASSERT_EQ(log_context_num_fields(), 1U);
292 ASSERT_EQ(log_context_num_contexts(), 0U);
293 ASSERT_EQ(log_context_num_fields(), 0U);
296 static void test_log_prefix(void) {
298 LOG_SET_PREFIX("ABC");
305 LOG_SET_PREFIX("QED");
323 for (int target
= 0; target
< _LOG_TARGET_MAX
; target
++) {
324 log_set_target(target
);
335 DEFINE_TEST_MAIN(LOG_DEBUG
);