1 /*
2 * Copyright (c) 2020 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief Additional test case for log core
10 *
11 */
12
13 #include <zephyr/tc_util.h>
14 #include <stdbool.h>
15 #include <zephyr/kernel.h>
16 #include <zephyr/ztest.h>
17 #include <zephyr/logging/log_backend.h>
18 #include <zephyr/logging/log_backend_std.h>
19 #include <zephyr/logging/log_ctrl.h>
20 #include <zephyr/logging/log.h>
21 #include <zephyr/logging/log_output.h>
22 #include <zephyr/sys/iterable_sections.h>
23
24 #define TEST_MESSAGE "test msg"
25
26 #define LOG_MODULE_NAME log_test
27 LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF);
28 static K_SEM_DEFINE(log_sem, 0, 1);
29
30 #define TIMESTAMP_FREC (2000000)
31 ZTEST_BMEM uint32_t source_id;
32 /* used when log_msg create in user space */
33 ZTEST_BMEM uint8_t domain, level;
34 ZTEST_DMEM uint32_t msg_data = 0x1234;
35
36 static uint8_t buf;
char_out(uint8_t * data,size_t length,void * ctx)37 static int char_out(uint8_t *data, size_t length, void *ctx)
38 {
39 ARG_UNUSED(data);
40 ARG_UNUSED(ctx);
41 return length;
42 }
43 LOG_OUTPUT_DEFINE(log_output, char_out, &buf, 1);
44
45 struct backend_cb {
46 /* count log messages handled by this backend */
47 size_t counter;
48 /* count log messages handled immediately by this backend */
49 size_t sync;
50 /* inform put() to check timestamp of message against exp_timestamps */
51 bool check_timestamp;
52 uint32_t exp_timestamps[16];
53 /* inform put() to check severity of message against exp_severity */
54 bool check_severity;
55 uint16_t exp_severity[4];
56 /* inform put() to check domain_id of message */
57 bool check_domain_id;
58 /* How many messages have been logged.
59 * used in async mode, to make sure all logs have been handled by compare
60 * counter with total_logs
61 */
62 size_t total_logs;
63 };
64
process(const struct log_backend * const backend,union log_msg_generic * msg)65 static void process(const struct log_backend *const backend,
66 union log_msg_generic *msg)
67 {
68 uint32_t flags;
69 struct backend_cb *cb = (struct backend_cb *)backend->cb->ctx;
70
71 /* If printk message skip it. */
72 if (log_msg_get_level(&(msg->log)) == LOG_LEVEL_INTERNAL_RAW_STRING) {
73 return;
74 }
75
76 if (IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE)) {
77 cb->sync++;
78 }
79
80 if (cb->check_domain_id) {
81 zassert_equal(log_msg_get_domain(&(msg->log)), Z_LOG_LOCAL_DOMAIN_ID,
82 "Unexpected domain id");
83 }
84
85 if (cb->check_timestamp) {
86 uint32_t exp_timestamp = cb->exp_timestamps[cb->counter];
87
88 zassert_equal(log_msg_get_timestamp(&(msg->log)), exp_timestamp,
89 "Unexpected message index");
90 }
91
92 if (cb->check_severity) {
93 zassert_equal(log_msg_get_level(&(msg->log)),
94 cb->exp_severity[cb->counter],
95 "Unexpected log severity");
96 }
97
98 cb->counter++;
99 if (IS_ENABLED(CONFIG_LOG_PROCESS_THREAD)) {
100 if (cb->counter == cb->total_logs) {
101 k_sem_give(&log_sem);
102 }
103 }
104
105 if (k_is_user_context()) {
106 zassert_equal(log_msg_get_domain(&(msg->log)), domain,
107 "Unexpected domain id");
108
109 zassert_equal(log_msg_get_level(&(msg->log)), level,
110 "Unexpected log severity");
111 }
112
113 flags = log_backend_std_get_flags();
114 log_output_msg_process(&log_output, &msg->log, flags);
115 }
116
panic(const struct log_backend * const backend)117 static void panic(const struct log_backend *const backend)
118 {
119 ARG_UNUSED(backend);
120 }
121
122 const struct log_backend_api log_backend_test_api = {
123 .process = process,
124 .panic = panic,
125 };
126
127 LOG_BACKEND_DEFINE(backend1, log_backend_test_api, false);
128 struct backend_cb backend1_cb;
129
130 LOG_BACKEND_DEFINE(backend2, log_backend_test_api, false);
131 struct backend_cb backend2_cb;
132
133 /* The logging system support user customize timestamping in log messages
134 * by register a timestamp function, in timestamp_get() below, just return
135 * a counter as timestamp for different messages.
136 * when install this timestamp function, timestamping frequency is set to
137 * 2000000, means 2 timestamp/us
138 */
139 #ifndef CONFIG_USERSPACE
140 static uint32_t stamp;
timestamp_get(void)141 static uint32_t timestamp_get(void)
142 {
143 stamp++;
144 return log_output_timestamp_to_us(stamp * 2);
145 }
146
log_setup(bool backend2_enable)147 static void log_setup(bool backend2_enable)
148 {
149 stamp = 0U;
150
151 log_init();
152 #ifndef CONFIG_LOG_PROCESS_THREAD
153 log_thread_set(k_current_get());
154 #endif
155
156 memset(&backend1_cb, 0, sizeof(backend1_cb));
157
158 log_backend_enable(&backend1, &backend1_cb, LOG_LEVEL_DBG);
159
160 if (backend2_enable) {
161 memset(&backend2_cb, 0, sizeof(backend2_cb));
162
163 log_backend_enable(&backend2, &backend2_cb, LOG_LEVEL_DBG);
164 } else {
165 log_backend_disable(&backend2);
166 }
167 }
168
169 #endif
170
log_test_process(void)171 static bool log_test_process(void)
172 {
173 if (IS_ENABLED(CONFIG_LOG_PROCESS_THREAD)) {
174 /* waiting for all logs have been handled */
175 k_sem_take(&log_sem, K_FOREVER);
176 return false;
177 } else {
178 return log_process();
179 }
180 }
181
182 /**
183 * @brief Support multi-processor systems
184 *
185 * @details Logging system identify domain/processor by domain_id which is now
186 * statically configured by Z_LOG_LOCAL_DOMAIN_ID
187 *
188 * @addtogroup logging
189 */
190
191 #ifndef CONFIG_USERSPACE
192
193 /**
194 * @brief Create Tests for Dynamic Loadable Logging Backends
195 *
196 * @details Test the three APIs, log_backend_activate, log_backend_is_active and
197 * log_backend_deactivate.
198 *
199 * @addtogroup logging
200 */
ZTEST(test_log_core_additional,test_log_backend)201 ZTEST(test_log_core_additional, test_log_backend)
202 {
203 log_init();
204
205 zassert_false(log_backend_is_active(&backend1));
206 log_backend_activate(&backend1, NULL);
207 zassert_true(log_backend_is_active(&backend1));
208 log_backend_deactivate(&backend1);
209 zassert_false(log_backend_is_active(&backend1));
210 }
211
ZTEST(test_log_core_additional,test_log_domain_id)212 ZTEST(test_log_core_additional, test_log_domain_id)
213 {
214 log_setup(false);
215
216 backend1_cb.check_domain_id = true;
217 backend1_cb.total_logs = 1;
218
219 LOG_INF("info message for domain id test");
220
221 while (log_test_process()) {
222 }
223
224 zassert_equal(backend1_cb.total_logs, backend1_cb.counter,
225 "Unexpected amount of messages received by the backend");
226 }
227
228 /**
229 * @brief Synchronous processing of logging messages.
230 *
231 * @details if CONFIG_LOG_MODE_IMMEDIATE is enabled, log message is
232 * handled immediately
233 *
234 * @addtogroup logging
235 */
ZTEST(test_log_core_additional,test_log_sync)236 ZTEST(test_log_core_additional, test_log_sync)
237 {
238 TC_PRINT("Logging synchronously\n");
239
240 if (IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE)) {
241 log_setup(false);
242 LOG_INF("Log immediately");
243 LOG_INF("Log immediately");
244
245 /* log immediately, no log_process needed */
246 zassert_equal(2, backend1_cb.sync,
247 "Unexpected amount of messages received by the backend.");
248 } else {
249 ztest_test_skip();
250 }
251 }
252
253 /**
254 * @brief Early logging
255 * @details Handle log message attempts as well as creating new log contexts
256 * instance, before the backend are active
257 *
258 * @addtogroup logging
259 */
ZTEST(test_log_core_additional,test_log_early_logging)260 ZTEST(test_log_core_additional, test_log_early_logging)
261 {
262 if (IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE)) {
263 ztest_test_skip();
264 } else {
265 log_init();
266
267 /* deactivate other backends */
268 STRUCT_SECTION_FOREACH(log_backend, backend) {
269 if (strcmp(backend->name, "test")) {
270 log_backend_deactivate(backend);
271 }
272 }
273
274 TC_PRINT("Create log message before backend active\n");
275
276 LOG_INF("log info before backend active");
277 LOG_WRN("log warn before backend active");
278 LOG_ERR("log error before backend active");
279
280 TC_PRINT("Activate backend with context");
281 memset(&backend1_cb, 0, sizeof(backend1_cb));
282 backend1_cb.total_logs = 3;
283 log_backend_enable(&backend1, &backend1_cb, LOG_LEVEL_DBG);
284
285 while (log_test_process()) {
286 }
287
288 zassert_equal(backend1_cb.total_logs, backend1_cb.counter,
289 "Unexpected amount of messages received. %d",
290 backend1_cb.counter);
291 }
292 }
293
294 /**
295 * @brief Log severity
296 *
297 * @details This module is registered with LOG_LEVEL_INF, LOG_LEVEL_DBG will be
298 * filtered out at compile time, only 3 message handled
299 *
300 * @addtogroup logging
301 */
ZTEST(test_log_core_additional,test_log_severity)302 ZTEST(test_log_core_additional, test_log_severity)
303 {
304 log_setup(false);
305
306 backend1_cb.check_severity = true;
307 backend1_cb.exp_severity[0] = LOG_LEVEL_INF;
308 backend1_cb.exp_severity[1] = LOG_LEVEL_WRN;
309 backend1_cb.exp_severity[2] = LOG_LEVEL_ERR;
310
311 LOG_INF("info message");
312 LOG_WRN("warning message");
313 LOG_ERR("error message");
314 backend1_cb.total_logs = 3;
315
316 while (log_test_process()) {
317 }
318
319 zassert_equal(backend1_cb.total_logs, backend1_cb.counter,
320 "Unexpected amount of messages received by the backend.");
321 }
322
323 /**
324 * @brief Customizable timestamping in log messages
325 *
326 * @details Log core permit user to register customized timestamp function
327 *
328 * @addtogroup logging
329 */
ZTEST(test_log_core_additional,test_log_timestamping)330 ZTEST(test_log_core_additional, test_log_timestamping)
331 {
332 stamp = 0U;
333
334 log_init();
335 /* deactivate all other backend */
336 STRUCT_SECTION_FOREACH(log_backend, backend) {
337 if ((backend == &backend1) || (backend == &backend2)) {
338 log_backend_deactivate(backend);
339 }
340 }
341
342 TC_PRINT("Register timestamp function\n");
343 zassert_equal(-EINVAL, log_set_timestamp_func(NULL, 0),
344 "Expects successful timestamp function setting.");
345 zassert_equal(0, log_set_timestamp_func(timestamp_get, TIMESTAMP_FREC),
346 "Expects successful timestamp function setting.");
347
348 memset(&backend1_cb, 0, sizeof(backend1_cb));
349 log_backend_enable(&backend1, &backend1_cb, LOG_LEVEL_DBG);
350
351 backend1_cb.check_timestamp = true;
352
353 backend1_cb.exp_timestamps[0] = 1U;
354 backend1_cb.exp_timestamps[1] = 2U;
355 backend1_cb.exp_timestamps[2] = 3U;
356
357 LOG_INF("test timestamp");
358 LOG_INF("test timestamp");
359 LOG_WRN("test timestamp");
360 backend1_cb.total_logs = 3;
361
362 while (log_test_process()) {
363 }
364
365 zassert_equal(backend1_cb.total_logs,
366 backend1_cb.counter,
367 "Unexpected amount of messages received by the backend.");
368 }
369
370 /**
371 * @brief Multiple logging backends
372 *
373 * @details Enable two backends in this module and enable UART backend
374 * by CONFIG_LOG_BACKEND_UART, there are three backends at least.
375 *
376 * @addtogroup logging
377 */
378
379 #define UART_BACKEND "log_backend_uart"
ZTEST(test_log_core_additional,test_multiple_backends)380 ZTEST(test_log_core_additional, test_multiple_backends)
381 {
382 int cnt;
383
384 TC_PRINT("Test multiple backends");
385 /* enable both backend1 and backend2 */
386 log_setup(true);
387 STRUCT_SECTION_COUNT(log_backend, &cnt);
388 zassert_true((cnt >= 2),
389 "There is no multi backends");
390
391 if (IS_ENABLED(CONFIG_LOG_BACKEND_UART)) {
392 bool have_uart = false;
393
394 STRUCT_SECTION_FOREACH(log_backend, backend) {
395 if (strcmp(backend->name, UART_BACKEND) == 0) {
396 have_uart = true;
397 }
398 }
399 zassert_true(have_uart, "There is no UART log backend found");
400 }
401 }
402
403 /**
404 * @brief Process all logging activities using a dedicated thread
405 *
406 * @addtogroup logging
407 */
408
409 #ifdef CONFIG_LOG_PROCESS_THREAD
ZTEST(test_log_core_additional,test_log_thread)410 ZTEST(test_log_core_additional, test_log_thread)
411 {
412 TC_PRINT("Logging buffer is configured to %d bytes\n",
413 CONFIG_LOG_BUFFER_SIZE);
414
415 TC_PRINT("Stack size of logging thread is configured by ");
416 TC_PRINT("CONFIG_LOG_PROCESS_THREAD_STACK_SIZE: %d bytes\n",
417 CONFIG_LOG_PROCESS_THREAD_STACK_SIZE);
418
419 log_setup(false);
420
421 zassert_false(log_data_pending());
422
423 LOG_INF("log info to log thread");
424 LOG_WRN("log warning to log thread");
425 LOG_ERR("log error to log thread");
426
427 zassert_true(log_data_pending());
428
429 /* wait 2 seconds for logging thread to handle this log message*/
430 k_sleep(K_MSEC(2000));
431 zassert_equal(3, backend1_cb.counter,
432 "Unexpected amount of messages received by the backend.");
433 zassert_false(log_data_pending());
434 }
435 #else
ZTEST(test_log_core_additional,test_log_thread)436 ZTEST(test_log_core_additional, test_log_thread)
437 {
438 ztest_test_skip();
439 }
440 #endif
441
442 /**
443 * @brief Process all logging activities using a dedicated thread (trigger immediate processing)
444 *
445 * @addtogroup logging
446 */
447
448 #ifdef CONFIG_LOG_PROCESS_THREAD
ZTEST(test_log_core_additional,test_log_thread_trigger)449 ZTEST(test_log_core_additional, test_log_thread_trigger)
450 {
451 log_setup(false);
452
453 zassert_false(log_data_pending());
454
455 LOG_INF("log info to log thread");
456 LOG_WRN("log warning to log thread");
457 LOG_ERR("log error to log thread");
458
459 zassert_true(log_data_pending());
460
461 /* Trigger log thread to process messages as soon as possible. */
462 log_thread_trigger();
463
464 /* wait 1ms to give logging thread chance to handle these log messages. */
465 k_sleep(K_MSEC(1));
466 zassert_equal(3, backend1_cb.counter,
467 "Unexpected amount of messages received by the backend.");
468 zassert_false(log_data_pending());
469 }
470 #else
ZTEST(test_log_core_additional,test_log_thread_trigger)471 ZTEST(test_log_core_additional, test_log_thread_trigger)
472 {
473 ztest_test_skip();
474 }
475 #endif
476
call_log_generic(const char * fmt,...)477 static void call_log_generic(const char *fmt, ...)
478 {
479 va_list ap;
480
481 va_start(ap, fmt);
482 log_generic(LOG_LEVEL_INF, fmt, ap);
483 va_end(ap);
484 }
485
ZTEST(test_log_core_additional,test_log_generic)486 ZTEST(test_log_core_additional, test_log_generic)
487 {
488 char *log_msg = "log user space";
489 int i = 100;
490
491 log_setup(false);
492 backend1_cb.total_logs = 4;
493
494 call_log_generic("log generic");
495 call_log_generic("log generic: %s", log_msg);
496 call_log_generic("log generic %d\n", i);
497 call_log_generic("log generic %d, %d\n", i, 1);
498 while (log_test_process()) {
499 }
500 }
501
ZTEST(test_log_core_additional,test_log_msg_create)502 ZTEST(test_log_core_additional, test_log_msg_create)
503 {
504 log_setup(false);
505 if (IS_ENABLED(CONFIG_LOG_MODE_DEFERRED)) {
506 int mode;
507
508 domain = 3;
509 level = 2;
510
511 z_log_msg_runtime_create(domain, __log_current_const_data,
512 level, &msg_data, 0,
513 sizeof(msg_data), NULL);
514 /* try z_log_msg_static_create() */
515 Z_LOG_MSG_STACK_CREATE(0, domain, __log_current_const_data,
516 level, &msg_data,
517 sizeof(msg_data), NULL);
518
519 Z_LOG_MSG_CREATE(!IS_ENABLED(CONFIG_USERSPACE), mode,
520 Z_LOG_LOCAL_DOMAIN_ID, NULL,
521 LOG_LEVEL_INF, NULL, 0, TEST_MESSAGE);
522
523 backend1_cb.total_logs = 3;
524
525 while (log_test_process()) {
526 }
527 }
528 }
529
530 #else
531
ZTEST_USER(test_log_core_additional,test_log_msg_create_user)532 ZTEST_USER(test_log_core_additional, test_log_msg_create_user)
533 {
534 int mode;
535
536 domain = 3;
537 level = 2;
538
539 z_log_msg_runtime_create(domain, NULL,
540 level, &msg_data, 0,
541 sizeof(msg_data), TEST_MESSAGE);
542 /* try z_log_msg_static_create() */
543 Z_LOG_MSG_STACK_CREATE(0, domain, NULL,
544 level, &msg_data,
545 sizeof(msg_data), TEST_MESSAGE);
546
547 Z_LOG_MSG_CREATE(!IS_ENABLED(CONFIG_USERSPACE), mode,
548 Z_LOG_LOCAL_DOMAIN_ID, NULL,
549 LOG_LEVEL_INTERNAL_RAW_STRING, NULL, 0, TEST_MESSAGE);
550
551 while (log_test_process()) {
552 }
553 }
554
555 #endif /** CONFIG_USERSPACE **/
556
557 /* The log process thread has the K_LOWEST_APPLICATION_THREAD_PRIO, adjust it
558 * to a higher priority to increase the chances of being scheduled to handle
559 * log message as soon as possible
560 */
promote_log_thread(const struct k_thread * thread,void * user_data)561 void promote_log_thread(const struct k_thread *thread, void *user_data)
562 {
563 if (!(strcmp(thread->name, "logging"))) {
564 k_thread_priority_set((k_tid_t)thread, -1);
565 }
566 }
567
test_log_core_additional_setup(void)568 static void *test_log_core_additional_setup(void)
569 {
570 #ifdef CONFIG_LOG_PROCESS_THREAD
571 k_thread_foreach(promote_log_thread, NULL);
572 #endif
573 return NULL;
574 }
575
576 ZTEST_SUITE(test_log_core_additional, NULL, test_log_core_additional_setup, NULL, NULL, NULL);
577