Skip to content

Commit 63c596f

Browse files
WIP: Add zephyr logging to ztest
This is a demo PR for the TSC based on a conversation on the #testing channel in the Discord. * Define a set of ztest logging macros (ZTEST_ERR, ZTEST_WRN, etc) that get used globally. * Add a Kconfig for choosing between Zephyr logging framework and built-in printk() logging (only supported in new ztest API) * Transistion ztest log outputs to these new macros at the appropriate levels. ### TODO * There's a lot of test output happening in tc_util.h, which isn't part of ztest and has its own printk macro wrapper. Need to find a nice way to override that. * Various other TODOs and thoughts added in comments. * Strip newlines from log messages since logging subsystem adds its own. Zephyr logging has been enabled in the `tests/ztest/base/` tests, which you can run with `/workdir/zephyr/scripts/twister -T /workdir/zephyr/tests/ztest/base -vvv` for dev purposes.
1 parent d2a56c5 commit 63c596f

File tree

12 files changed

+152
-51
lines changed

12 files changed

+152
-51
lines changed

subsys/testsuite/include/tc_util.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,27 @@
1717
#endif
1818
#include <sys/printk.h>
1919

20+
#if defined(CONFIG_ZTEST) && defined(CONFIG_ZTEST_PRINT_TO_LOG)
21+
/* Override the PRINT_DATA and TC_END_REPORT macros to use Zephyr's
22+
* logging system. Use ZTEST_PRINTK() (i.e. always print) for
23+
* TC_END_REPORT() because that line is critical for twister to
24+
* determine when tests running within QEMU have completed.
25+
*/
26+
27+
#include <ztest.h>
28+
29+
#define PRINT_DATA ZTEST_INF
30+
31+
#define TC_END_REPORT(result) \
32+
do { \
33+
PRINT_LINE; \
34+
TC_PRINT_RUNID; \
35+
ZTEST_PRINTK("PROJECT EXECUTION %s\n", \
36+
(result) == TC_PASS ? "SUCCESSFUL" : "FAILED"); \
37+
TC_END_POST(result); \
38+
} while (0)
39+
#endif
40+
2041
#if defined CONFIG_ZTEST_TC_UTIL_USER_OVERRIDE
2142
#include <tc_util_user_override.h>
2243
#endif

subsys/testsuite/ztest/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@ config ZTEST
1010

1111
if ZTEST
1212

13+
config ZTEST_PRINT_TO_LOG
14+
bool "Use the Zephyr logging subsystem"
15+
depends on LOG
16+
depends on ZTEST_NEW_API
17+
help
18+
If enabled, the ZTEST logging macros (ZTEST_ERR, ZTEST_WRN, etc) will be
19+
forwarded to the Zephyr logging subsystem at the corresponding levels.
20+
The verbosity level of these logs can be controlled using the normal
21+
Zephyr log Kconfig options. A console logging backend will be attached.
22+
23+
If disabled, all log messages using the ZTEST logging macros will be
24+
directed to printk(). There is no control over verbosity in this case.
25+
1326
config ZTEST_NEW_API
1427
bool "Use the new Ztest API"
1528
help

subsys/testsuite/ztest/include/ztest.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,37 @@ typedef struct esf z_arch_esf_t;
5454
#endif /* KERNEL */
5555

5656
#include <sys/printk.h>
57+
58+
/* Test logging destination */
59+
#ifdef CONFIG_ZTEST_PRINT_TO_LOG
60+
/* Use the Zephyr logging subsystem */
61+
#include <logging/log.h>
62+
63+
#ifndef ZTEST_DONT_DECLARE_LOG
64+
/* Automatically declare the log module in all compilation units including
65+
* this header, unless this macro is set. The macro should be set in the
66+
* source file that initially registers the module to avoid a redefinition.
67+
*/
68+
69+
LOG_MODULE_DECLARE(ztest_log_mod);
70+
#endif /* ZTEST_DONT_DECLARE_LOG */
71+
72+
73+
#define ZTEST_DBG LOG_DBG
74+
#define ZTEST_INF LOG_INF
75+
#define ZTEST_WRN LOG_WRN
76+
#define ZTEST_ERR LOG_ERR
77+
#define ZTEST_PRINTK LOG_PRINTK
78+
#else
79+
/* Direct everything through printk */
80+
#define ZTEST_DBG printk
81+
#define ZTEST_INF printk
82+
#define ZTEST_WRN printk
83+
#define ZTEST_ERR printk
84+
#define ZTEST_PRINTK printk
85+
#endif /* ZTEST_PRINT_TO_LOG */
86+
87+
/* TODO: Do we want to retain this? Could user tests be relying on it? */
5788
#define PRINT printk
5889

5990
#include <zephyr.h>

subsys/testsuite/ztest/include/ztest_assert.h

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ void ztest_test_fail(void);
3030
static inline bool z_zassert_(bool cond, const char *file, int line)
3131
{
3232
if (cond == false) {
33-
PRINT("\n Assertion failed at %s:%d\n",
33+
ZTEST_ERR("\n Assertion failed at %s:%d\n",
3434
ztest_relative_filename(file), line);
3535
ztest_test_fail();
3636
return false;
@@ -50,21 +50,29 @@ static inline bool z_zassert(bool cond,
5050
int line, const char *func,
5151
const char *msg, ...)
5252
{
53+
static char formatted_msg[512]; /* TODO: is this the right size? */
54+
5355
if (cond == false) {
5456
va_list vargs;
57+
int ret;
5558

5659
va_start(vargs, msg);
57-
PRINT("\n Assertion failed at %s:%d: %s: %s\n",
58-
ztest_relative_filename(file), line, func, default_msg);
59-
vprintk(msg, vargs);
60-
printk("\n");
60+
ZTEST_ERR("\n Assertion failed at %s:%d: %s: %s\n",
61+
ztest_relative_filename(file), line, func, default_msg);
62+
63+
ret = vsnprintf(formatted_msg, sizeof(formatted_msg), msg, vargs);
64+
if (ret >= sizeof(formatted_msg)) {
65+
ZTEST_ERR("The assertion message has been truncated!\n");
66+
}
67+
ZTEST_ERR("%s\n", formatted_msg);
6168
va_end(vargs);
6269
ztest_test_fail();
6370
return false;
6471
}
72+
/* TODO - is this config option still relevant? */
6573
#if CONFIG_ZTEST_ASSERT_VERBOSE == 2
6674
else {
67-
PRINT("\n Assertion succeeded at %s:%d (%s)\n",
75+
ZTEST_DBG("\n Assertion succeeded at %s:%d (%s)\n",
6876
ztest_relative_filename(file), line, func);
6977
}
7078
#endif

subsys/testsuite/ztest/src/ztest.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,11 @@ static int cleanup_test(struct unit_test *test)
7575
#endif
7676

7777
if (!ret && mock_status == 1) {
78-
PRINT("Test %s failed: Unused mock parameter values\n",
78+
ZTEST_ERR("Test %s failed: Unused mock parameter values\n",
7979
test->name);
8080
ret = TC_FAIL;
8181
} else if (!ret && mock_status == 2) {
82-
PRINT("Test %s failed: Unused mock return values\n",
82+
ZTEST_ERR("Test %s failed: Unused mock return values\n",
8383
test->name);
8484
ret = TC_FAIL;
8585
} else {
@@ -244,15 +244,15 @@ static void handle_signal(int sig)
244244
"teardown",
245245
};
246246

247-
PRINT(" %s", strsignal(sig));
247+
ZTEST_ERR(" %s", strsignal(sig));
248248
switch (phase) {
249249
case TEST_PHASE_SETUP:
250250
case TEST_PHASE_TEST:
251251
case TEST_PHASE_TEARDOWN:
252-
PRINT(" at %s function\n", phase_str[phase]);
252+
ZTEST_ERR(" at %s function\n", phase_str[phase]);
253253
longjmp(test_fail, 1);
254254
case TEST_PHASE_FRAMEWORK:
255-
PRINT("\n");
255+
ZTEST_ERR("\n");
256256
longjmp(stack_fail, 1);
257257
}
258258
}
@@ -263,7 +263,7 @@ static void init_testing(void)
263263
signal(SIGSEGV, handle_signal);
264264

265265
if (setjmp(stack_fail)) {
266-
PRINT("Test suite crashed.");
266+
ZTEST_ERR("Test suite crashed.");
267267
exit(1);
268268
}
269269
}
@@ -482,7 +482,7 @@ void ztest_verify_all_registered_test_suites_ran(void)
482482

483483
for (ptr = _ztest_suite_node_list_start; ptr < _ztest_suite_node_list_end; ++ptr) {
484484
if (ptr->stats.run_count < 1) {
485-
PRINT("ERROR: Test '%s' did not run.\n", ptr->name);
485+
ZTEST_ERR("ERROR: Test '%s' did not run.\n", ptr->name);
486486
all_tests_run = false;
487487
}
488488
}
@@ -521,7 +521,8 @@ void main(void)
521521
ret = k_mem_domain_add_partition(&k_mem_domain_default,
522522
&ztest_mem_partition);
523523
if (ret != 0) {
524-
PRINT("ERROR: failed to add ztest_mem_partition to mem domain (%d)\n",
524+
ZTEST_ERR(
525+
"ERROR: failed to add ztest_mem_partition to mem domain (%d)\n",
525526
ret);
526527
k_oops();
527528
}
@@ -530,7 +531,8 @@ void main(void)
530531
ret = k_mem_domain_add_partition(&k_mem_domain_default,
531532
&z_malloc_partition);
532533
if (ret != 0) {
533-
PRINT("ERROR: failed to add z_malloc_partition to mem domain (%d)\n",
534+
ZTEST_ERR(
535+
"ERROR: failed to add z_malloc_partition to mem domain (%d)\n",
534536
ret);
535537
k_oops();
536538
}
@@ -553,12 +555,12 @@ void main(void)
553555
}
554556
state.boots += 1;
555557
if (test_status == 0) {
556-
PRINT("Reset board #%u to test again\n",
558+
ZTEST_ERR("Reset board #%u to test again\n",
557559
state.boots);
558560
k_msleep(10);
559561
sys_reboot(SYS_REBOOT_COLD);
560562
} else {
561-
PRINT("Failed after %u attempts\n", state.boots);
563+
ZTEST_ERR("Failed after %u attempts\n", state.boots);
562564
state.boots = 0;
563565
}
564566
}

subsys/testsuite/ztest/src/ztest_error_hook.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,18 @@ void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *pEsf)
5151
k_tid_t curr_tid = k_current_get();
5252
bool valid_fault = (curr_tid == valid_fault_tid) || fault_in_isr;
5353

54-
printk("Caught system error -- reason %d %d\n", reason, valid_fault);
54+
ZTEST_ERR("Caught system error -- reason %d %d\n", reason, valid_fault);
5555

5656
if (valid_fault) {
57-
printk("Fatal error expected as part of test case.\n");
57+
ZTEST_ERR("Fatal error expected as part of test case.\n");
5858

5959
/* reset back to normal */
6060
reset_stored_fault_status();
6161

6262
/* do some action after expected fatal error happened */
6363
ztest_post_fatal_error_hook(reason, pEsf);
6464
} else {
65-
printk("Fatal error was unexpected, aborting...\n");
65+
ZTEST_ERR("Fatal error was unexpected, aborting...\n");
6666
k_fatal_halt(reason);
6767
}
6868
}
@@ -119,10 +119,10 @@ void assert_post_action(const char *file, unsigned int line)
119119
ARG_UNUSED(line);
120120
#endif
121121

122-
printk("Caught assert failed\n");
122+
ZTEST_ERR("Caught assert failed\n");
123123

124124
if ((k_current_get() == valid_assert_tid) || assert_in_isr) {
125-
printk("Assert error expected as part of test case.\n");
125+
ZTEST_ERR("Assert error expected as part of test case.\n");
126126

127127
/* reset back to normal */
128128
reset_stored_assert_status();
@@ -132,7 +132,7 @@ void assert_post_action(const char *file, unsigned int line)
132132
*/
133133
ztest_post_assert_fail_hook();
134134
} else {
135-
printk("Assert failed was unexpected, aborting...\n");
135+
ZTEST_ERR("Assert failed was unexpected, aborting...\n");
136136
#ifdef CONFIG_USERSPACE
137137
/* User threads aren't allowed to induce kernel panics; generate
138138
* an oops instead.

subsys/testsuite/ztest/src/ztest_mock.c

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7+
#ifdef CONFIG_ZTEST_PRINT_TO_LOG
8+
#include <logging/log.h>
9+
10+
LOG_MODULE_DECLARE(ztest_log_mod);
11+
#endif /* CONFIG_ZTEST_PRINT_TO_LOG */
12+
713
#include <ztest.h>
814
#include <zephyr/types.h>
915
#include <string.h>
@@ -32,7 +38,7 @@ static struct parameter *alloc_parameter(void)
3238

3339
param = calloc(1, sizeof(struct parameter));
3440
if (!param) {
35-
PRINT("Failed to allocate mock parameter\n");
41+
ZTEST_ERR("Failed to allocate mock parameter\n");
3642
ztest_test_fail();
3743
}
3844

@@ -122,7 +128,7 @@ static struct parameter *alloc_parameter(void)
122128
allocation_index = sys_bitfield_find_first_clear(
123129
params_allocation, CONFIG_ZTEST_PARAMETER_COUNT);
124130
if (allocation_index == -1) {
125-
printk("No more mock parameters available for allocation\n");
131+
ZTEST_ERR("No more mock parameters available for allocation\n");
126132
ztest_test_fail();
127133
}
128134
sys_bitfield_set_bit((mem_addr_t)params_allocation, allocation_index);
@@ -193,7 +199,7 @@ void z_ztest_check_expected_value(const char *fn, const char *name,
193199

194200
param = find_and_delete_value(&parameter_list, fn, name);
195201
if (!param) {
196-
PRINT("Failed to find parameter %s for %s\n", name, fn);
202+
ZTEST_ERR("Failed to find parameter %s for %s\n", name, fn);
197203
ztest_test_fail();
198204
}
199205

@@ -204,7 +210,7 @@ void z_ztest_check_expected_value(const char *fn, const char *name,
204210
/* We need to cast these values since the toolchain doesn't
205211
* provide inttypes.h
206212
*/
207-
PRINT("%s:%s received wrong value: Got %lu, expected %lu\n", fn,
213+
ZTEST_ERR("%s:%s received wrong value: Got %lu, expected %lu\n", fn,
208214
name, (unsigned long)val, (unsigned long)expected);
209215
ztest_test_fail();
210216
}
@@ -223,7 +229,7 @@ void z_ztest_check_expected_data(const char *fn, const char *name, void *data,
223229

224230
param = find_and_delete_value(&parameter_list, fn, name);
225231
if (!param) {
226-
PRINT("Failed to find parameter %s for %s\n", name, fn);
232+
ZTEST_ERR("Failed to find parameter %s for %s\n", name, fn);
227233
/* No return from this function but for coverity reasons
228234
* put a return after to avoid the warning of a null
229235
* dereference of param below.
@@ -236,15 +242,15 @@ void z_ztest_check_expected_data(const char *fn, const char *name, void *data,
236242
free_parameter(param);
237243

238244
if (expected == NULL && data != NULL) {
239-
PRINT("%s:%s received null pointer\n", fn, name);
245+
ZTEST_ERR("%s:%s received null pointer\n", fn, name);
240246
ztest_test_fail();
241247
} else if (data == NULL && expected != NULL) {
242-
PRINT("%s:%s received data while expected null pointer\n", fn,
248+
ZTEST_ERR("%s:%s received data while expected null pointer\n", fn,
243249
name);
244250
ztest_test_fail();
245251
} else if (data != NULL) {
246252
if (memcmp(data, expected, length) != 0) {
247-
PRINT("%s:%s data provided don't match\n", fn, name);
253+
ZTEST_ERR("%s:%s data provided don't match\n", fn, name);
248254
ztest_test_fail();
249255
}
250256
}
@@ -262,14 +268,14 @@ void z_ztest_copy_return_data(const char *fn, const char *name, void *data,
262268
void *return_data;
263269

264270
if (data == NULL) {
265-
PRINT("%s:%s received null pointer\n", fn, name);
271+
ZTEST_ERR("%s:%s received null pointer\n", fn, name);
266272
ztest_test_fail();
267273
return;
268274
}
269275

270276
param = find_and_delete_value(&parameter_list, fn, name);
271277
if (!param) {
272-
PRINT("Failed to find parameter %s for %s\n", name, fn);
278+
ZTEST_ERR("Failed to find parameter %s for %s\n", name, fn);
273279
memset(data, 0, length);
274280
ztest_test_fail();
275281
} else {
@@ -291,7 +297,7 @@ uintptr_t z_ztest_get_return_value(const char *fn)
291297
find_and_delete_value(&return_value_list, fn, "");
292298

293299
if (!param) {
294-
PRINT("Failed to find return value for function %s\n", fn);
300+
ZTEST_ERR("Failed to find return value for function %s\n", fn);
295301
ztest_test_fail();
296302
}
297303

@@ -317,13 +323,13 @@ int z_cleanup_mock(void)
317323
int fail = 0;
318324

319325
if (parameter_list.next) {
320-
PRINT("Parameter not used by mock: %s:%s\n",
326+
ZTEST_ERR("Parameter not used by mock: %s:%s\n",
321327
parameter_list.next->fn,
322328
parameter_list.next->name);
323329
fail = 1;
324330
}
325331
if (return_value_list.next) {
326-
PRINT("Return value no used by mock: %s\n",
332+
ZTEST_ERR("Return value no used by mock: %s\n",
327333
return_value_list.next->fn);
328334
fail = 2;
329335
}

0 commit comments

Comments
 (0)