1 /*
2 * Copyright (c) 2021 Nordic Semiconductor
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "mock_backend.h"
8 #include "mock_frontend.h"
9 #include "test_module.h"
10 #include <zephyr/ztest.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/logging/log_ctrl.h>
13 #include <zephyr/sys/cbprintf.h>
14
15 #ifndef CONFIG_LOG_BUFFER_SIZE
16 #define CONFIG_LOG_BUFFER_SIZE 4
17 #endif
18
19 #ifndef NO_BACKENDS
20 #define NO_BACKENDS 0
21 #endif
22
23 LOG_MODULE_REGISTER(test, CONFIG_SAMPLE_MODULE_LOG_LEVEL);
24
25 #ifdef CONFIG_LOG_USE_TAGGED_ARGUMENTS
26 /* The extra sizeof(int) is the end of arguments tag. */
27 #define LOG_SIMPLE_MSG_LEN \
28 ROUND_UP(sizeof(struct log_msg) + \
29 sizeof(struct cbprintf_package_hdr_ext) + \
30 sizeof(int) + (IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC) ? 1 : 0), \
31 CBPRINTF_PACKAGE_ALIGNMENT)
32 #else
33 #define LOG_SIMPLE_MSG_LEN \
34 ROUND_UP(sizeof(struct log_msg) + \
35 sizeof(struct cbprintf_package_hdr_ext) + \
36 (IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC) ? 1 : 0), \
37 CBPRINTF_PACKAGE_ALIGNMENT)
38 #endif
39
40 #ifdef CONFIG_LOG_TIMESTAMP_64BIT
41 #define TIMESTAMP_INIT_VAL 0x100000000
42 #else
43 #define TIMESTAMP_INIT_VAL 0
44 #endif
45
46 #if NO_BACKENDS
47 static struct log_backend backend1;
48 static struct log_backend backend2;
49 #else
50 MOCK_LOG_BACKEND_DEFINE(backend1, false);
51 MOCK_LOG_BACKEND_DEFINE(backend2, false);
52 #endif
53
54 static log_timestamp_t stamp;
55 static bool in_panic;
56 static int16_t test_source_id;
57 static int16_t test2_source_id;
58
timestamp_get(void)59 static log_timestamp_t timestamp_get(void)
60 {
61 return NO_BACKENDS ? (log_timestamp_t)UINT32_MAX : stamp++;
62 }
63
64 /**
65 * @brief Flush logs.
66 *
67 * If processing thread is enabled keep sleeping until there are no pending messages
68 * else process logs here.
69 */
flush_log(void)70 static void flush_log(void)
71 {
72 if (IS_ENABLED(CONFIG_LOG_PROCESS_THREAD)) {
73 while (log_data_pending()) {
74 k_msleep(10);
75 }
76 k_msleep(100);
77 } else {
78 while (LOG_PROCESS()) {
79 }
80 }
81 }
82
frontend_only(void)83 static bool frontend_only(void)
84 {
85 return NO_BACKENDS || IS_ENABLED(CONFIG_LOG_FRONTEND_ONLY);
86 }
87
log_setup(bool backend2_enable)88 static void log_setup(bool backend2_enable)
89 {
90 stamp = TIMESTAMP_INIT_VAL;
91 zassert_false(in_panic, "Logger in panic state.");
92
93 log_core_init();
94 if (!IS_ENABLED(CONFIG_LOG_PROCESS_THREAD)) {
95 log_init();
96 }
97
98 zassert_equal(0, log_set_timestamp_func(timestamp_get, 0),
99 "Expects successful timestamp function setting.");
100
101 mock_log_frontend_reset();
102
103 test_source_id = log_source_id_get(STRINGIFY(test));
104 test2_source_id = log_source_id_get(STRINGIFY(test2));
105
106 if (frontend_only()) {
107 return;
108 }
109
110 mock_log_backend_reset(&backend1);
111 mock_log_backend_reset(&backend2);
112
113 log_backend_enable(&backend1, backend1.cb->ctx, LOG_LEVEL_DBG);
114
115 if (backend2_enable) {
116 log_backend_enable(&backend2, backend2.cb->ctx, LOG_LEVEL_DBG);
117 } else {
118 log_backend_disable(&backend2);
119 }
120
121 }
122
123 /**
124 * @brief Process and validate that backends got expected content.
125 *
126 * @param backend2_enable If true backend2 is also validated.
127 * @param panic True means that logging is in panic mode, flushing is skipped.
128 */
process_and_validate(bool backend2_enable,bool panic)129 static void process_and_validate(bool backend2_enable, bool panic)
130 {
131 if (!panic) {
132 flush_log();
133 }
134
135 mock_log_frontend_validate(panic);
136
137 if (NO_BACKENDS) {
138 int cnt;
139
140 STRUCT_SECTION_COUNT(log_backend, &cnt);
141 zassert_equal(cnt, 0);
142 return;
143 }
144
145 if (IS_ENABLED(CONFIG_LOG_FRONTEND_ONLY)) {
146 return;
147 }
148
149 mock_log_backend_validate(&backend1, panic);
150
151 if (backend2_enable) {
152 mock_log_backend_validate(&backend2, panic);
153 }
154 }
155
dbg_enabled(void)156 static bool dbg_enabled(void)
157 {
158 return IS_ENABLED(CONFIG_SAMPLE_MODULE_LOG_LEVEL_DBG) || (CONFIG_LOG_OVERRIDE_LEVEL == 4);
159 }
160
ZTEST(test_log_api,test_log_various_messages)161 ZTEST(test_log_api, test_log_various_messages)
162 {
163 char str[128];
164 char dstr[] = "abcd";
165 int8_t i = -5;
166 log_timestamp_t exp_timestamp = TIMESTAMP_INIT_VAL;
167
168 log_setup(false);
169
170 unsigned long long ull = 0x1122334455667799;
171 long long ll = -12313213214454545;
172
173 #define TEST_MSG_0 "%lld %llu %hhd"
174 #define TEST_MSG_0_PREFIX "%s: %lld %llu %hhd"
175 #define TEST_MSG_1 "%f %d %f"
176
177 if (dbg_enabled()) {
178 /* If prefix is enabled, add function name prefix */
179 if (IS_ENABLED(CONFIG_LOG_FUNC_NAME_PREFIX_DBG)) {
180 snprintk(str, sizeof(str),
181 TEST_MSG_0_PREFIX, __func__, ll, ull, i);
182 } else {
183 snprintk(str, sizeof(str), TEST_MSG_0, ll, ull, i);
184 }
185
186 mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_DBG, str);
187 mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(),
188 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_DBG,
189 exp_timestamp++, str);
190 }
191
192 LOG_DBG(TEST_MSG_0, ll, ull, i);
193
194 #ifdef CONFIG_FPU
195 float f = -1.2356f;
196 double d = -1.2356;
197
198 snprintk(str, sizeof(str), TEST_MSG_1, (double)f, 100, d);
199 mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_INF, str);
200 mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(),
201 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_INF,
202 exp_timestamp++, str);
203
204 LOG_INF(TEST_MSG_1, (double)f, 100, d);
205 #endif /* CONFIG_FPU */
206
207 snprintk(str, sizeof(str), "wrn %s", dstr);
208 mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_WRN, str);
209 mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(),
210 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_WRN,
211 exp_timestamp++, str);
212
213 mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_ERR, "err");
214 mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(),
215 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_ERR,
216 exp_timestamp++, "err");
217
218 LOG_WRN("wrn %s", dstr);
219 dstr[0] = '\0';
220
221 LOG_ERR("err");
222
223 process_and_validate(false, false);
224
225 #undef TEST_MSG_0
226 #undef TEST_MSG_0_PREFIX
227 #undef TEST_MSG_1
228 }
229
230 /*
231 * Test is using 2 backends and runtime filtering is enabled. After first call
232 * filtering for backend2 is reduced to warning. It is expected that next INFO
233 * level log message will be passed only to backend1.
234 */
ZTEST(test_log_api,test_log_backend_runtime_filtering)235 ZTEST(test_log_api, test_log_backend_runtime_filtering)
236 {
237 uint16_t s_id = LOG_CURRENT_MODULE_ID();
238 uint8_t d_id = Z_LOG_LOCAL_DOMAIN_ID;
239 log_timestamp_t exp_ts = TIMESTAMP_INIT_VAL;
240
241 if (!IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING)) {
242 ztest_test_skip();
243 }
244
245 log_setup(true);
246
247 if (dbg_enabled()) {
248 char str[128];
249
250 /* If prefix is enabled, add function name prefix */
251 if (IS_ENABLED(CONFIG_LOG_FUNC_NAME_PREFIX_DBG)) {
252 snprintk(str, sizeof(str),
253 "%s: test", __func__);
254 } else {
255 snprintk(str, sizeof(str), "test");
256 }
257
258 mock_log_frontend_record(s_id, LOG_LEVEL_DBG, str);
259 if (!frontend_only()) {
260 mock_log_backend_record(&backend1, s_id, d_id, LOG_LEVEL_DBG, exp_ts, str);
261 mock_log_backend_record(&backend2, s_id, d_id, LOG_LEVEL_DBG, exp_ts, str);
262 }
263 exp_ts++;
264 }
265
266 mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_INF, "test");
267 if (!frontend_only()) {
268 mock_log_backend_record(&backend1, s_id, d_id, LOG_LEVEL_INF, exp_ts, "test");
269 mock_log_backend_record(&backend2, s_id, d_id, LOG_LEVEL_INF, exp_ts, "test");
270 }
271 exp_ts++;
272
273 LOG_DBG("test");
274 LOG_INF("test");
275
276 process_and_validate(true, false);
277
278 uint32_t exp_level1 = dbg_enabled() ? LOG_LEVEL_DBG : LOG_LEVEL_INF;
279 uint32_t exp_level2 = LOG_LEVEL_WRN;
280
281 uint32_t b_level;
282 uint32_t f_level;
283
284 /* Validate levels before changing for backend2 and frontend */
285 if (!frontend_only()) {
286 b_level = log_filter_get(&backend1, d_id, s_id, true);
287 zassert_equal(b_level, exp_level1);
288
289 b_level = log_filter_get(&backend2, d_id, s_id, true);
290 zassert_equal(b_level, exp_level1);
291 }
292
293 if (IS_ENABLED(CONFIG_LOG_FRONTEND)) {
294 f_level = log_frontend_filter_get(s_id, true);
295 zassert_equal(f_level, exp_level1);
296
297 log_frontend_filter_set(s_id, LOG_LEVEL_WRN);
298
299 f_level = log_frontend_filter_get(s_id, true);
300 zassert_equal(f_level, exp_level2);
301 }
302
303 if (!frontend_only()) {
304 log_filter_set(&backend2, d_id, s_id, LOG_LEVEL_WRN);
305
306 b_level = log_filter_get(&backend1, d_id, s_id, true);
307 zassert_equal(b_level, exp_level1);
308
309 b_level = log_filter_get(&backend2, d_id, s_id, true);
310 zassert_equal(b_level, exp_level2);
311 }
312
313 uint8_t data[] = {1, 2, 4, 5, 6, 8};
314
315 if (!frontend_only()) {
316 /* INF logs expected only on backend1 */
317 mock_log_backend_record(&backend1, s_id, d_id, LOG_LEVEL_INF, exp_ts++, "test");
318
319 mock_log_backend_generic_record(&backend1, s_id, d_id, LOG_LEVEL_INF,
320 exp_ts++, "hexdump", data, sizeof(data));
321 }
322
323 /* WRN message expected on backends and frontend */
324 mock_log_frontend_record(s_id, LOG_LEVEL_WRN, "test2");
325 if (!frontend_only()) {
326 mock_log_backend_record(&backend1, s_id, d_id, LOG_LEVEL_WRN, exp_ts, "test2");
327 mock_log_backend_record(&backend2, s_id, d_id, LOG_LEVEL_WRN, exp_ts++, "test2");
328 }
329
330 mock_log_frontend_generic_record(s_id, d_id, LOG_LEVEL_WRN, "hexdump", data, sizeof(data));
331 if (!frontend_only()) {
332 mock_log_backend_generic_record(&backend1, s_id, d_id, LOG_LEVEL_WRN,
333 exp_ts, "hexdump", data, sizeof(data));
334 mock_log_backend_generic_record(&backend2, s_id, d_id, LOG_LEVEL_WRN,
335 exp_ts++, "hexdump", data, sizeof(data));
336 }
337
338 LOG_INF("test");
339 LOG_HEXDUMP_INF(data, sizeof(data), "hexdump");
340 LOG_WRN("test2");
341 LOG_HEXDUMP_WRN(data, sizeof(data), "hexdump");
342
343 process_and_validate(true, false);
344 }
345
get_max_hexdump(void)346 static size_t get_max_hexdump(void)
347 {
348 return CONFIG_LOG_BUFFER_SIZE - sizeof(struct log_msg_hdr);
349 }
350
351 #if defined(CONFIG_ARCH_POSIX)
352 #define STR_SIZE(s) (strlen(s) + 2 * sizeof(char))
353 #else
354 #define STR_SIZE(s) 0
355 #endif
356
get_long_hexdump(void)357 static size_t get_long_hexdump(void)
358 {
359 size_t extra_msg_sz = 0;
360 size_t extra_hexdump_sz = 0;
361
362 if (IS_ENABLED(CONFIG_LOG_USE_TAGGED_ARGUMENTS)) {
363 /* First message with 2 arguments => 2 tags */
364 extra_msg_sz = 2 * sizeof(int);
365
366 /*
367 * Hexdump with an implicit "%s" and the "hexdump" string
368 * as argument => 1 tag.
369 */
370 extra_hexdump_sz = sizeof(int);
371 }
372 if (IS_ENABLED(CONFIG_TEST_LOG_MSG_APPEND_RO_STRING_LOC)) {
373 extra_msg_sz += sizeof(uint8_t); /* Location of format string. */
374 }
375
376 return CONFIG_LOG_BUFFER_SIZE -
377 /* First message */
378 ROUND_UP(LOG_SIMPLE_MSG_LEN + 2 * sizeof(int) + extra_msg_sz,
379 CBPRINTF_PACKAGE_ALIGNMENT) -
380 /* Hexdump message excluding data */
381 ROUND_UP(LOG_SIMPLE_MSG_LEN + STR_SIZE("hexdump") + extra_hexdump_sz,
382 CBPRINTF_PACKAGE_ALIGNMENT);
383 }
384
385 /*
386 * When LOG_MODE_OVERFLOW is enabled, logger should discard oldest messages when
387 * there is no room. However, if after discarding all messages there is still no
388 * room then current log is discarded.
389 */
390 static uint8_t log_buf[CONFIG_LOG_BUFFER_SIZE];
391
ZTEST(test_log_api,test_log_overflow)392 ZTEST(test_log_api, test_log_overflow)
393 {
394 log_timestamp_t exp_timestamp = TIMESTAMP_INIT_VAL;
395
396 log_setup(false);
397
398 if (IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE)) {
399 ztest_test_skip();
400 }
401
402 if (!IS_ENABLED(CONFIG_LOG_MODE_OVERFLOW)) {
403 ztest_test_skip();
404 }
405
406 for (int i = 0; i < CONFIG_LOG_BUFFER_SIZE; i++) {
407 log_buf[i] = i;
408 }
409
410 uint32_t hexdump_len = get_long_hexdump();
411
412 /* expect first message to be dropped */
413 exp_timestamp++;
414 mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_INF, "test 100 100");
415 mock_log_frontend_generic_record(LOG_CURRENT_MODULE_ID(), Z_LOG_LOCAL_DOMAIN_ID,
416 LOG_LEVEL_INF, "hexdump", log_buf, hexdump_len);
417 mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_INF, "test2");
418 mock_log_backend_generic_record(&backend1, LOG_CURRENT_MODULE_ID(),
419 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_INF,
420 exp_timestamp++, "hexdump",
421 log_buf, hexdump_len);
422 mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(),
423 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_INF,
424 exp_timestamp++, "test2");
425 mock_log_backend_drop_record(&backend1, 1);
426
427 LOG_INF("test %d %d", 100, 100);
428 LOG_HEXDUMP_INF(log_buf, hexdump_len, "hexdump");
429 LOG_INF("test2");
430
431 process_and_validate(false, false);
432
433 log_setup(false);
434
435 exp_timestamp = TIMESTAMP_INIT_VAL;
436 hexdump_len = get_max_hexdump();
437 mock_log_backend_reset(&backend1);
438 mock_log_frontend_reset();
439
440 mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_INF, "test");
441 mock_log_frontend_generic_record(LOG_CURRENT_MODULE_ID(), Z_LOG_LOCAL_DOMAIN_ID,
442 LOG_LEVEL_INF, "test", log_buf, hexdump_len + 1);
443 /* Log2 allocation is not destructive if request exceeds the
444 * capacity.
445 */
446 mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(),
447 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_INF,
448 exp_timestamp, "test");
449 mock_log_backend_drop_record(&backend1, 1);
450
451 LOG_INF("test");
452 LOG_HEXDUMP_INF(log_buf, hexdump_len + 1, "test");
453
454 process_and_validate(false, false);
455
456 }
457
458 /*
459 * Test checks if arguments are correctly processed by the logger.
460 *
461 * Log messages with supported number of messages are called. Test backend and
462 * frontend validate number of arguments and values.
463 */
464 #define MOCK_LOG_FRONT_BACKEND_RECORD(str) do { \
465 mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(), \
466 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_INF, \
467 exp_timestamp++, str); \
468 mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_INF, str); \
469 } while (0)
470
ZTEST(test_log_api,test_log_arguments)471 ZTEST(test_log_api, test_log_arguments)
472 {
473 log_timestamp_t exp_timestamp = TIMESTAMP_INIT_VAL;
474
475 log_setup(false);
476
477 MOCK_LOG_FRONT_BACKEND_RECORD("test");
478 MOCK_LOG_FRONT_BACKEND_RECORD("test 1 2 3");
479 MOCK_LOG_FRONT_BACKEND_RECORD("test 1 2 3 4");
480 MOCK_LOG_FRONT_BACKEND_RECORD("test 1 2 3 4 5");
481
482 LOG_INF("test");
483 LOG_INF("test %d %d %d", 1, 2, 3);
484 LOG_INF("test %d %d %d %d", 1, 2, 3, 4);
485 LOG_INF("test %d %d %d %d %d", 1, 2, 3, 4, 5);
486
487 process_and_validate(false, false);
488
489 MOCK_LOG_FRONT_BACKEND_RECORD("test 1 2 3 4 5 6");
490 MOCK_LOG_FRONT_BACKEND_RECORD("test 1 2 3 4 5 6 7");
491 MOCK_LOG_FRONT_BACKEND_RECORD("test 1 2 3 4 5 6 7 8");
492 MOCK_LOG_FRONT_BACKEND_RECORD("test 1 2 3 4 5 6 7 8 9");
493
494 LOG_INF("test %d %d %d %d %d %d", 1, 2, 3, 4, 5, 6);
495 LOG_INF("test %d %d %d %d %d %d %d", 1, 2, 3, 4, 5, 6, 7);
496 LOG_INF("test %d %d %d %d %d %d %d %d", 1, 2, 3, 4, 5, 6, 7, 8);
497 LOG_INF("test %d %d %d %d %d %d %d %d %d", 1, 2, 3, 4, 5, 6, 7, 8, 9);
498
499 process_and_validate(false, false);
500
501 MOCK_LOG_FRONT_BACKEND_RECORD("test 1 2 3 4 5 6 7 8 9 10");
502 MOCK_LOG_FRONT_BACKEND_RECORD("test 1 2 3 4 5 6 7 8 9 10 11");
503
504 LOG_INF("test %d %d %d %d %d %d %d %d %d %d",
505 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
506 LOG_INF("test %d %d %d %d %d %d %d %d %d %d %d",
507 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
508
509 process_and_validate(false, false);
510
511 MOCK_LOG_FRONT_BACKEND_RECORD("test 1 2 3 4 5 6 7 8 9 10 11 12");
512 MOCK_LOG_FRONT_BACKEND_RECORD("test 1 2 3 4 5 6 7 8 9 10 11 12 13");
513
514 LOG_INF("test %d %d %d %d %d %d %d %d %d %d %d %d",
515 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
516
517 LOG_INF("test %d %d %d %d %d %d %d %d %d %d %d %d %d",
518 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
519
520 process_and_validate(false, false);
521
522 MOCK_LOG_FRONT_BACKEND_RECORD("test 1 2 3 4 5 6 7 8 9 10 11 12 13 14");
523 LOG_INF("test %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
524 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
525
526 process_and_validate(false, false);
527 }
528
529 /* Function comes from the file which is part of test module. It is
530 * expected that logs coming from it will have same source_id as current
531 * module (this file).
532 */
ZTEST(test_log_api,test_log_from_declared_module)533 ZTEST(test_log_api, test_log_from_declared_module)
534 {
535 log_timestamp_t exp_timestamp = TIMESTAMP_INIT_VAL;
536
537 log_setup(false);
538
539 /* See test module for log message content. */
540 if (dbg_enabled()) {
541 char str[128];
542
543 /* If prefix is enabled, add function name prefix */
544 if (IS_ENABLED(CONFIG_LOG_FUNC_NAME_PREFIX_DBG)) {
545 snprintk(str, sizeof(str),
546 "%s: " TEST_DBG_MSG, "test_func");
547 } else {
548 snprintk(str, sizeof(str), TEST_DBG_MSG);
549 }
550
551 mock_log_frontend_record(test_source_id, LOG_LEVEL_DBG, str);
552 mock_log_backend_record(&backend1, test_source_id,
553 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_DBG,
554 exp_timestamp++, str);
555 }
556
557 mock_log_frontend_record(test_source_id, LOG_LEVEL_ERR, TEST_ERR_MSG);
558 mock_log_backend_record(&backend1, test_source_id,
559 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_ERR,
560 exp_timestamp++, TEST_ERR_MSG);
561
562 test_func();
563
564 if (dbg_enabled()) {
565 char str[128];
566
567 /* If prefix is enabled, add function name prefix */
568 if (IS_ENABLED(CONFIG_LOG_FUNC_NAME_PREFIX_DBG)) {
569 snprintk(str, sizeof(str),
570 "%s: " TEST_INLINE_DBG_MSG, "test_inline_func");
571 } else {
572 snprintk(str, sizeof(str), TEST_INLINE_DBG_MSG);
573 }
574
575 mock_log_frontend_record(test_source_id, LOG_LEVEL_DBG, str);
576 mock_log_backend_record(&backend1, test_source_id,
577 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_DBG,
578 exp_timestamp++, str);
579 }
580
581 mock_log_frontend_record(test_source_id, LOG_LEVEL_ERR, TEST_INLINE_ERR_MSG);
582 mock_log_backend_record(&backend1, test_source_id,
583 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_ERR,
584 exp_timestamp, TEST_INLINE_ERR_MSG);
585
586 test_inline_func();
587
588 process_and_validate(false, false);
589
590 }
591
592 /** Calculate how many messages will fit in the buffer. Also calculate if
593 * remaining free space is size of message or not. This impacts how many messages
594 * are dropped. If free space is equal to message size then when buffer is full,
595 * adding new message will lead to one message drop, otherwise 2 message will
596 * be dropped.
597 */
get_short_msg_capacity(void)598 static size_t get_short_msg_capacity(void)
599 {
600 return CONFIG_LOG_BUFFER_SIZE / LOG_SIMPLE_MSG_LEN;
601 }
602
log_n_messages(uint32_t n_msg,uint32_t exp_dropped)603 static void log_n_messages(uint32_t n_msg, uint32_t exp_dropped)
604 {
605 printk("ex dropped:%d\n", exp_dropped);
606 log_timestamp_t exp_timestamp = TIMESTAMP_INIT_VAL;
607
608 log_setup(false);
609
610 stamp = TIMESTAMP_INIT_VAL;
611
612 for (uint32_t i = 0; i < n_msg; i++) {
613 mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_INF, "dummy");
614 if (i >= exp_dropped) {
615 mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(),
616 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_INF,
617 exp_timestamp, "dummy");
618 }
619 exp_timestamp++;
620 LOG_INF("dummy");
621 }
622
623 mock_log_backend_drop_record(&backend1, exp_dropped);
624
625 process_and_validate(false, false);
626 mock_log_backend_reset(&backend1);
627 }
628
629 /*
630 * Test checks if backend receives notification about dropped messages. It
631 * first blocks threads to ensure full control of log processing time and
632 * then logs certain log messages, expecting dropped notification.
633 *
634 * With multiple cpus you may not get consistent message dropping
635 * as other core may process logs. Executing on 1 cpu only.
636 */
ZTEST(test_log_api_1cpu,test_log_msg_dropped_notification)637 ZTEST(test_log_api_1cpu, test_log_msg_dropped_notification)
638 {
639 log_setup(false);
640
641 if (IS_ENABLED(CONFIG_SMP)) {
642 /* With smp you may not get consistent message dropping as other
643 * core may process logs.
644 */
645 ztest_test_skip();
646 }
647
648 if (IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE)) {
649 ztest_test_skip();
650 }
651
652 if (!IS_ENABLED(CONFIG_LOG_MODE_OVERFLOW)) {
653 ztest_test_skip();
654 }
655
656 uint32_t capacity = get_short_msg_capacity();
657
658 log_n_messages(capacity, 0);
659
660 /* Expect messages dropped when logger more than buffer capacity. */
661 log_n_messages(capacity + 1, 1);
662 log_n_messages(capacity + 2, 2);
663 }
664
665 /* Test checks if panic is correctly executed. On panic logger should flush all
666 * messages and process logs in place (not in deferred way).
667 */
ZTEST(test_log_api,test_log_panic)668 ZTEST(test_log_api, test_log_panic)
669 {
670 log_timestamp_t exp_timestamp = TIMESTAMP_INIT_VAL;
671
672 log_setup(false);
673
674 mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_WRN, "test");
675 mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_WRN, "test");
676 mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(),
677 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_WRN,
678 exp_timestamp++, "test");
679 mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(),
680 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_WRN,
681 exp_timestamp++, "test");
682 LOG_WRN("test");
683 LOG_WRN("test");
684
685 /* logs should be flushed in panic */
686 log_panic();
687
688 process_and_validate(false, true);
689
690 /* messages processed where called */
691 mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_WRN, "test");
692 mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(),
693 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_WRN,
694 exp_timestamp++, "test");
695 LOG_WRN("test");
696
697 process_and_validate(false, true);
698 }
699
ZTEST(test_log_api,test_log_printk)700 ZTEST(test_log_api, test_log_printk)
701 {
702 if (!IS_ENABLED(CONFIG_LOG_PRINTK)) {
703 ztest_test_skip();
704 }
705
706 log_timestamp_t exp_timestamp = TIMESTAMP_INIT_VAL;
707
708 log_setup(false);
709
710 mock_log_backend_record(&backend1, 0,
711 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_INTERNAL_RAW_STRING,
712 exp_timestamp++, "test 100");
713 printk("test %d", 100);
714
715 log_panic();
716
717 mock_log_backend_record(&backend1, 0,
718 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_INTERNAL_RAW_STRING,
719 exp_timestamp++, "test 101");
720 printk("test %d", 101);
721
722 process_and_validate(false, true);
723 }
724
ZTEST(test_log_api,test_log_printk_vs_raw)725 ZTEST(test_log_api, test_log_printk_vs_raw)
726 {
727 log_timestamp_t exp_timestamp = TIMESTAMP_INIT_VAL;
728
729 log_setup(false);
730
731 mock_log_frontend_record(0, LOG_LEVEL_INTERNAL_RAW_STRING, "test 100\n");
732 mock_log_backend_record(&backend1, 0,
733 0, LOG_LEVEL_INTERNAL_RAW_STRING,
734 exp_timestamp++, "test 100\n");
735 LOG_PRINTK("test %d\n", 100);
736
737
738 mock_log_frontend_record(1, LOG_LEVEL_INTERNAL_RAW_STRING, "test 100\n");
739 mock_log_backend_record(&backend1, 1,
740 0, LOG_LEVEL_INTERNAL_RAW_STRING,
741 exp_timestamp++, "test 100\n");
742 LOG_RAW("test %d\n", 100);
743
744
745 process_and_validate(false, false);
746 }
747
ZTEST(test_log_api,test_log_arg_evaluation)748 ZTEST(test_log_api, test_log_arg_evaluation)
749 {
750 char str[128];
751 #define TEST_MSG_0 "%u %u"
752 #define TEST_MSG_0_PREFIX "%s: %u %u"
753 log_timestamp_t exp_timestamp = TIMESTAMP_INIT_VAL;
754 uint32_t cnt0 = 0;
755 uint32_t cnt1 = 0;
756 uint32_t exp0 = 1;
757 uint32_t exp1 = 1;
758
759 log_setup(false);
760
761 if (dbg_enabled()) {
762 /* Debug message arguments are only evaluated when this level
763 * is enabled.
764 */
765 exp0++;
766 exp1++;
767 }
768
769 mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_INF, "0 0");
770 mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(),
771 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_INF,
772 exp_timestamp++, "0 0");
773 if (dbg_enabled()) {
774 /* If prefix is enabled, add function name prefix */
775 if (IS_ENABLED(CONFIG_LOG_FUNC_NAME_PREFIX_DBG)) {
776 snprintk(str, sizeof(str),
777 TEST_MSG_0_PREFIX, __func__, 1, 1);
778 } else {
779 snprintk(str, sizeof(str), TEST_MSG_0, 1, 1);
780 }
781 mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_DBG, str);
782 mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(),
783 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_DBG,
784 exp_timestamp++, str);
785 }
786 /* Arguments used for logging shall be evaluated only once. They should
787 * be evaluated also when given log level is disabled.
788 */
789 LOG_INF("%u %u", cnt0++, cnt1++);
790 LOG_DBG("%u %u", cnt0++, cnt1++);
791
792 zassert_equal(cnt0, exp0, "Got:%u, Expected:%u", cnt0, exp0);
793 zassert_equal(cnt1, exp1, "Got:%u, Expected:%u", cnt1, exp1);
794
795 process_and_validate(false, false);
796 #undef TEST_MSG_0
797 #undef TEST_MSG_0_PREFIX
798 }
799
log_wrn_once_run(int i)800 static void log_wrn_once_run(int i)
801 {
802 LOG_WRN_ONCE("once %d", i);
803 }
804
ZTEST(test_log_api,test_log_wrn_once)805 ZTEST(test_log_api, test_log_wrn_once)
806 {
807 log_timestamp_t exp_timestamp = TIMESTAMP_INIT_VAL;
808
809 log_setup(false);
810
811 mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_WRN, "once 0");
812 mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(),
813 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_WRN,
814 exp_timestamp++, "once 0");
815
816 log_wrn_once_run(0);
817 log_wrn_once_run(1);
818 log_wrn_once_run(2);
819
820 process_and_validate(false, false);
821 }
822
ZTEST(test_log_api,test_log_override_level)823 ZTEST(test_log_api, test_log_override_level)
824 {
825 log_timestamp_t exp_timestamp = TIMESTAMP_INIT_VAL;
826
827 log_setup(false);
828
829 if (CONFIG_LOG_OVERRIDE_LEVEL == 4) {
830 char str[128];
831
832 /* If prefix is enabled, add function name prefix */
833 if (IS_ENABLED(CONFIG_LOG_FUNC_NAME_PREFIX_DBG)) {
834 snprintk(str, sizeof(str),
835 "%s: " TEST_DBG_MSG, "test_func");
836 } else {
837 snprintk(str, sizeof(str), TEST_DBG_MSG);
838 }
839
840 mock_log_frontend_record(test2_source_id, LOG_LEVEL_DBG, str);
841 mock_log_backend_record(&backend1, test2_source_id,
842 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_DBG,
843 exp_timestamp++, str);
844
845 mock_log_frontend_record(test2_source_id, LOG_LEVEL_ERR, TEST_ERR_MSG);
846 mock_log_backend_record(&backend1, test2_source_id,
847 Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_ERR,
848 exp_timestamp++, TEST_ERR_MSG);
849 } else if (CONFIG_LOG_OVERRIDE_LEVEL != 0) {
850 zassert_true(false, "Unexpected configuration.");
851 }
852
853 test_func2();
854
855 process_and_validate(false, false);
856 }
857
858 /* Disable backends because same suite may be executed again but compiled by C++ */
log_api_suite_teardown(void * data)859 static void log_api_suite_teardown(void *data)
860 {
861 ARG_UNUSED(data);
862
863 if (NO_BACKENDS) {
864 return;
865 }
866
867 log_backend_disable(&backend1);
868 log_backend_disable(&backend2);
869 }
870
log_api_suite_setup(void)871 static void *log_api_suite_setup(void)
872 {
873 PRINT("Configuration:\n");
874 PRINT("\t Mode: %s\n",
875 IS_ENABLED(CONFIG_LOG_FRONTEND_ONLY) ? "Frontend only" :
876 (IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE) ? "Immediate" : "Deferred"));
877 PRINT("\t Frontend: %s\n",
878 IS_ENABLED(CONFIG_LOG_FRONTEND) ? "Yes" : "No");
879 PRINT("\t Runtime filtering: %s\n",
880 IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING) ? "yes" : "no");
881 PRINT("\t Overwrite: %s\n",
882 IS_ENABLED(CONFIG_LOG_MODE_OVERFLOW) ? "yes" : "no");
883 if (NO_BACKENDS) {
884 PRINT("\t No backends\n");
885 }
886 #if __cplusplus
887 PRINT("\t C++: yes\n");
888 #endif
889 flush_log();
890
891 return NULL;
892 }
893
log_api_suite_before(void * data)894 static void log_api_suite_before(void *data)
895 {
896 ARG_UNUSED(data);
897
898 if (NO_BACKENDS) {
899 return;
900 }
901
902 /* Flush logs and enable test backends. */
903 flush_log();
904
905 if (IS_ENABLED(CONFIG_LOG_FRONTEND)) {
906 mock_log_frontend_check_enable();
907 }
908 mock_log_backend_check_enable(&backend1);
909 mock_log_backend_check_enable(&backend2);
910 }
911
log_api_suite_before_1cpu(void * data)912 static void log_api_suite_before_1cpu(void *data)
913 {
914 ztest_simple_1cpu_before(data);
915 log_api_suite_before(data);
916 }
917
log_api_suite_after(void * data)918 static void log_api_suite_after(void *data)
919 {
920 ARG_UNUSED(data);
921 if (NO_BACKENDS) {
922 return;
923 }
924
925 /* Disable testing backends after the test. Otherwise test may fail due
926 * to unexpected log message.
927 */
928 if (IS_ENABLED(CONFIG_LOG_FRONTEND)) {
929 mock_log_frontend_check_disable();
930 }
931 mock_log_backend_check_disable(&backend1);
932 mock_log_backend_check_disable(&backend2);
933 }
934
log_api_suite_after_1cpu(void * data)935 static void log_api_suite_after_1cpu(void *data)
936 {
937 log_api_suite_after(data);
938 ztest_simple_1cpu_after(data);
939 }
940
941 ZTEST_SUITE(test_log_api, NULL, log_api_suite_setup,
942 log_api_suite_before, log_api_suite_after, log_api_suite_teardown);
943
944 /* Suite dedicated for tests that need to run on 1 cpu only. */
945 ZTEST_SUITE(test_log_api_1cpu, NULL, log_api_suite_setup,
946 log_api_suite_before_1cpu, log_api_suite_after_1cpu, log_api_suite_teardown);
947