tests: ztest: add a common fatal and assert hook for special purpose
This is in order to reduce the redundancy code writing for fatal and assert handler for error case testing. They can be used both in kernel and userspace, and are also SMP safe. Signed-off-by: Enjia Mai <enjiax.mai@intel.com>
This commit is contained in:
parent
e396fd77a6
commit
a420cb4fd5
5 changed files with 241 additions and 1 deletions
|
@ -143,5 +143,4 @@ config TEST_ARM_CORTEX_M
|
||||||
the testing suite to utilize these exceptions, in tests.
|
the testing suite to utilize these exceptions, in tests.
|
||||||
Note that by default, when building with ARM_SECURE_FIRMWARE
|
Note that by default, when building with ARM_SECURE_FIRMWARE
|
||||||
set, these exceptions are set to target the Non-Secure state.
|
set, these exceptions are set to target the Non-Secure state.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -7,4 +7,5 @@ zephyr_include_directories(
|
||||||
|
|
||||||
zephyr_library()
|
zephyr_library()
|
||||||
zephyr_library_sources( src/ztest.c)
|
zephyr_library_sources( src/ztest.c)
|
||||||
|
zephyr_library_sources( src/ztest_error_hook.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_ZTEST_MOCKING src/ztest_mock.c)
|
zephyr_library_sources_ifdef(CONFIG_ZTEST_MOCKING src/ztest_mock.c)
|
||||||
|
|
|
@ -54,6 +54,24 @@ config ZTEST_RETEST_IF_PASSED
|
||||||
may be used as an alternative to manual resets when
|
may be used as an alternative to manual resets when
|
||||||
attempting to reproduce an intermittent failure.
|
attempting to reproduce an intermittent failure.
|
||||||
|
|
||||||
|
config ZTEST_FATAL_HOOK
|
||||||
|
bool "Using a pre-defined fatal handler and hook function"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Use the pre-defined common fatal error handler and a post hook to
|
||||||
|
do actions in your test case, this option often enabled when doing
|
||||||
|
error test case. Remember to add ignore_fault tag in yaml file when
|
||||||
|
using sanitycheck to run testing.
|
||||||
|
|
||||||
|
config ZTEST_ASSERT_HOOK
|
||||||
|
bool "Using a pre-defined assert handler and hook function"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Use the pre-defined common assert fail handler and a post hook to
|
||||||
|
do actions in your test case, this option often enabled when doing
|
||||||
|
error test case. Remember to add ignore_fault tag in yaml file when
|
||||||
|
using sanitycheck to run testing.
|
||||||
|
|
||||||
endif # ZTEST
|
endif # ZTEST
|
||||||
|
|
||||||
config ZTEST_MOCKING
|
config ZTEST_MOCKING
|
||||||
|
|
75
subsys/testsuite/ztest/include/ztest_error_hook.h
Normal file
75
subsys/testsuite/ztest/include/ztest_error_hook.h
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Intel Corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZEPHYR_INCLUDE_ZTEST_FATAL_HOOK_H_
|
||||||
|
#define ZEPHYR_INCLUDE_ZTEST_FATAL_HOOK_H_
|
||||||
|
|
||||||
|
#include <zephyr.h>
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CONFIG_ZTEST_FATAL_HOOK)
|
||||||
|
/**
|
||||||
|
* @brief Set the flag that treat fatal error happened as expected
|
||||||
|
*
|
||||||
|
* @details This is used for negative test cases which triggers a fatal
|
||||||
|
* error. Set the param true will still pass the test case when expected
|
||||||
|
* fatal error happened. For normal test case, set it false makes it back
|
||||||
|
* to normal behavior.
|
||||||
|
*
|
||||||
|
* @param valid flag indicate fault is expected
|
||||||
|
*/
|
||||||
|
__syscall void ztest_set_fault_valid(bool valid);
|
||||||
|
|
||||||
|
/* @brief A hook after fatal error handler
|
||||||
|
*
|
||||||
|
* @details This is a test case hook that can run code from test case, in
|
||||||
|
* order to deal with some special case when catching the expected fatal
|
||||||
|
* error.
|
||||||
|
*
|
||||||
|
* Usage: Define your own hook function in your test case code, and do what
|
||||||
|
* you want to do after fatal error handler.
|
||||||
|
*
|
||||||
|
* By default, it will do nothing before leaving error handler.
|
||||||
|
*/
|
||||||
|
void ztest_post_fatal_error_hook(unsigned int reason,
|
||||||
|
const z_arch_esf_t *pEsf);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CONFIG_ZTEST_ASSERT_HOOK)
|
||||||
|
/**
|
||||||
|
* @brief Set the flag that treat assert fail happened as expected
|
||||||
|
*
|
||||||
|
* @details This is used for negative test cases which triggers a assert
|
||||||
|
* fail. Set the param true will still pass the test case when expected
|
||||||
|
* assert fail happened. For normal test case, set it false make it back
|
||||||
|
* to normal behavior.
|
||||||
|
*
|
||||||
|
* @param valid flag indicate assert is expected
|
||||||
|
*/
|
||||||
|
__syscall void ztest_set_assert_valid(bool valid);
|
||||||
|
|
||||||
|
/* @brief A hook after assert fault handler
|
||||||
|
*
|
||||||
|
* @details This is a test case hook that can run code from test case, in
|
||||||
|
* order to deal with some special case when catching the expected assert
|
||||||
|
* failed.
|
||||||
|
*
|
||||||
|
* Usage: Define your own hook function in your test case code, and do what
|
||||||
|
* you want to do after assert handler.
|
||||||
|
*
|
||||||
|
* By default, it will abort the thread which assert failed.
|
||||||
|
*/
|
||||||
|
void ztest_post_assert_fail_hook(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_ZTEST_FATAL_HOOK)
|
||||||
|
#include <syscalls/ztest_error_hook.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ZEPHYR_INCLUDE_ZTEST_FATAL_HOOK_H_ */
|
147
subsys/testsuite/ztest/src/ztest_error_hook.c
Normal file
147
subsys/testsuite/ztest/src/ztest_error_hook.c
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Intel Corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#include <zephyr.h>
|
||||||
|
#include <ztest.h>
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CONFIG_ZTEST_FATAL_HOOK)
|
||||||
|
/* This is a flag indicate if treating fatal error as expected, then take
|
||||||
|
* action dealing with it. It's SMP-safe.
|
||||||
|
*/
|
||||||
|
ZTEST_BMEM volatile bool fault_in_isr;
|
||||||
|
ZTEST_BMEM volatile k_tid_t valid_fault_tid;
|
||||||
|
|
||||||
|
static inline void reset_stored_fault_status(void)
|
||||||
|
{
|
||||||
|
valid_fault_tid = NULL;
|
||||||
|
fault_in_isr = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void z_impl_ztest_set_fault_valid(bool valid)
|
||||||
|
{
|
||||||
|
if (valid) {
|
||||||
|
if (k_is_in_isr()) {
|
||||||
|
fault_in_isr = true;
|
||||||
|
} else {
|
||||||
|
valid_fault_tid = k_current_get();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reset_stored_fault_status();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_USERSPACE)
|
||||||
|
static inline void z_vrfy_ztest_set_fault_valid(bool valid)
|
||||||
|
{
|
||||||
|
z_impl_ztest_set_fault_valid(valid);
|
||||||
|
}
|
||||||
|
#include <syscalls/ztest_set_fault_valid_mrsh.c>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__weak void ztest_post_fatal_error_hook(unsigned int reason,
|
||||||
|
const z_arch_esf_t *pEsf)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *pEsf)
|
||||||
|
{
|
||||||
|
k_tid_t curr_tid = k_current_get();
|
||||||
|
bool valid_fault = (curr_tid == valid_fault_tid) || fault_in_isr;
|
||||||
|
|
||||||
|
printk("Caught system error -- reason %d %d\n", reason, valid_fault);
|
||||||
|
|
||||||
|
if (valid_fault) {
|
||||||
|
printk("Fatal error expected as part of test case.\n");
|
||||||
|
|
||||||
|
/* reset back to normal */
|
||||||
|
reset_stored_fault_status();
|
||||||
|
|
||||||
|
/* do some action after expected fatal error happened */
|
||||||
|
ztest_post_fatal_error_hook(reason, pEsf);
|
||||||
|
} else {
|
||||||
|
printk("Fatal error was unexpected, aborting...\n");
|
||||||
|
k_fatal_halt(reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CONFIG_ZTEST_ASSERT_HOOK)
|
||||||
|
/* This is a flag indicate if treating assert fail as expected, then take
|
||||||
|
* action dealing with it. It's SMP-safe.
|
||||||
|
*/
|
||||||
|
ZTEST_BMEM volatile bool assert_in_isr;
|
||||||
|
ZTEST_BMEM volatile k_tid_t valid_assert_tid;
|
||||||
|
|
||||||
|
static inline void reset_stored_assert_status(void)
|
||||||
|
{
|
||||||
|
valid_assert_tid = NULL;
|
||||||
|
assert_in_isr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void z_impl_ztest_set_assert_valid(bool valid)
|
||||||
|
{
|
||||||
|
if (valid) {
|
||||||
|
if (k_is_in_isr()) {
|
||||||
|
assert_in_isr = true;
|
||||||
|
} else {
|
||||||
|
valid_assert_tid = k_current_get();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reset_stored_assert_status();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_USERSPACE)
|
||||||
|
static inline void z_vrfy_ztest_set_assert_valid(bool valid)
|
||||||
|
{
|
||||||
|
z_impl_ztest_set_assert_valid(valid);
|
||||||
|
}
|
||||||
|
#include <syscalls/ztest_set_assert_valid_mrsh.c>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__weak void ztest_post_assert_fail_hook(void)
|
||||||
|
{
|
||||||
|
k_thread_abort(k_current_get());
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_ASSERT_NO_FILE_INFO
|
||||||
|
void assert_post_action(void)
|
||||||
|
#else
|
||||||
|
void assert_post_action(const char *file, unsigned int line)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#ifndef CONFIG_ASSERT_NO_FILE_INFO
|
||||||
|
ARG_UNUSED(file);
|
||||||
|
ARG_UNUSED(line);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
printk("Caught assert failed\n");
|
||||||
|
|
||||||
|
if ((k_current_get() == valid_assert_tid) || assert_in_isr) {
|
||||||
|
printk("Assert error expected as part of test case.\n");
|
||||||
|
|
||||||
|
/* reset back to normal */
|
||||||
|
reset_stored_assert_status();
|
||||||
|
|
||||||
|
/* It won't go back to caller when assert failed, and it
|
||||||
|
* will terminate the thread.
|
||||||
|
*/
|
||||||
|
ztest_post_assert_fail_hook();
|
||||||
|
} else {
|
||||||
|
printk("Assert failed was unexpected, aborting...\n");
|
||||||
|
#ifdef CONFIG_USERSPACE
|
||||||
|
/* User threads aren't allowed to induce kernel panics; generate
|
||||||
|
* an oops instead.
|
||||||
|
*/
|
||||||
|
if (_is_user_context()) {
|
||||||
|
k_oops();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
k_panic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
Add table
Add a link
Reference in a new issue