ztest: Fix userspace ztests in new API
Update the new API to use K_USER as the flags for both CONFIG_USERSPACE and CONFIG_TEST_USERSPACE. Also, fix the linker script to properly include the suites, tests, and rules. Fixes #44108 Signed-off-by: Yuval Peress <peress@google.com>
This commit is contained in:
parent
0becb666ef
commit
86cadf9283
23 changed files with 184 additions and 123 deletions
|
@ -8,3 +8,7 @@ zephyr_include_directories_ifdef(CONFIG_TEST
|
|||
add_subdirectory_ifdef(CONFIG_COVERAGE_GCOV coverage)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_TEST_BUSY_SIM busy_sim/busy_sim.c)
|
||||
|
||||
if(NOT BOARD STREQUAL unit_testing)
|
||||
zephyr_linker_sources(RODATA include/ztest.ld)
|
||||
endif()
|
||||
|
|
|
@ -3,26 +3,3 @@
|
|||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.data.ztest_suite_node_area : ALIGN(4)
|
||||
{
|
||||
_ztest_suite_node_list_start = .;
|
||||
KEEP(*(SORT_BY_NAME(._ztest_suite_node.static.*)))
|
||||
_ztest_suite_node_list_end = .;
|
||||
}
|
||||
.data.ztest_unit_test_area : ALIGN(4)
|
||||
{
|
||||
_ztest_unit_test_list_start = .;
|
||||
KEEP(*(SORT_BY_NAME(._ztest_unit_test.static.*)))
|
||||
_ztest_unit_test_list_end = .;
|
||||
}
|
||||
.data.ztest_test_rule_area : ALIGN(4)
|
||||
{
|
||||
_ztest_test_rule_list_start = .;
|
||||
KEEP(*(SORT_BY_NAME(._ztest_test_rule.static.*)))
|
||||
_ztest_test_rule_list_end = .;
|
||||
}
|
||||
}
|
||||
INSERT AFTER .data;
|
||||
|
|
28
subsys/testsuite/include/ztest_unittest.ld
Normal file
28
subsys/testsuite/include/ztest_unittest.ld
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.data.ztest_suite_node_area : ALIGN(4)
|
||||
{
|
||||
_ztest_suite_node_list_start = .;
|
||||
KEEP(*(SORT_BY_NAME(._ztest_suite_node.static.*)))
|
||||
_ztest_suite_node_list_end = .;
|
||||
}
|
||||
.data.ztest_unit_test_area : ALIGN(4)
|
||||
{
|
||||
_ztest_unit_test_list_start = .;
|
||||
KEEP(*(SORT_BY_NAME(._ztest_unit_test.static.*)))
|
||||
_ztest_unit_test_list_end = .;
|
||||
}
|
||||
.data.ztest_test_rule_area : ALIGN(4)
|
||||
{
|
||||
_ztest_test_rule_list_start = .;
|
||||
KEEP(*(SORT_BY_NAME(._ztest_test_rule.static.*)))
|
||||
_ztest_test_rule_list_end = .;
|
||||
}
|
||||
}
|
||||
INSERT AFTER .data;
|
|
@ -59,7 +59,7 @@ struct ztest_suite_node {
|
|||
*/
|
||||
bool (*predicate)(const void *state);
|
||||
/** Stats */
|
||||
struct ztest_suite_stats stats;
|
||||
struct ztest_suite_stats *stats;
|
||||
};
|
||||
|
||||
extern struct ztest_suite_node _ztest_suite_node_list_start[];
|
||||
|
@ -78,10 +78,12 @@ extern struct ztest_suite_node _ztest_suite_node_list_end[];
|
|||
*/
|
||||
#define ztest_register_test_suite(SUITE_NAME, PREDICATE, args...) \
|
||||
ztest_test_suite(SUITE_NAME, ##args); \
|
||||
struct ztest_suite_stats UTIL_CAT(z_ztest_test_node_stats_, SUITE_NAME); \
|
||||
static STRUCT_SECTION_ITERABLE(ztest_suite_node, z_ztest_test_node_##SUITE_NAME) = { \
|
||||
.name = #SUITE_NAME, \
|
||||
.suite = _##SUITE_NAME, \
|
||||
.predicate = PREDICATE, \
|
||||
.stats = &UTIL_CAT(z_ztest_test_node_stats_, SUITE_NAME), \
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,6 +17,12 @@
|
|||
#include <zephyr/init.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if defined(CONFIG_USERSPACE)
|
||||
#define __USERSPACE_FLAGS (K_USER)
|
||||
#else
|
||||
#define __USERSPACE_FLAGS (0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -30,6 +36,7 @@ struct ztest_unit_test {
|
|||
|
||||
extern struct ztest_unit_test _ztest_unit_test_list_start[];
|
||||
extern struct ztest_unit_test _ztest_unit_test_list_end[];
|
||||
#define ZTEST_TEST_COUNT (_ztest_unit_test_list_end - _ztest_unit_test_list_start)
|
||||
|
||||
/**
|
||||
* Stats about a ztest suite
|
||||
|
@ -49,31 +56,31 @@ struct ztest_suite_stats {
|
|||
*/
|
||||
struct ztest_suite_node {
|
||||
/** The name of the test suite. */
|
||||
const char *name;
|
||||
const char * const name;
|
||||
/**
|
||||
* Setup function to run before running this suite
|
||||
*
|
||||
* @return Pointer to the data structure that will be used throughout this test suite
|
||||
*/
|
||||
void *(*setup)(void);
|
||||
void *(*const setup)(void);
|
||||
/**
|
||||
* Function to run before each test in this suite
|
||||
*
|
||||
* @param data The test suite's data returned from setup()
|
||||
*/
|
||||
void (*before)(void *data);
|
||||
void (*const before)(void *data);
|
||||
/**
|
||||
* Function to run after each test in this suite
|
||||
*
|
||||
* @param data The test suite's data returned from setup()
|
||||
*/
|
||||
void (*after)(void *data);
|
||||
void (*const after)(void *data);
|
||||
/**
|
||||
* Teardown function to run after running this suite
|
||||
*
|
||||
* @param data The test suite's data returned from setup()
|
||||
*/
|
||||
void (*teardown)(void *data);
|
||||
void (*const teardown)(void *data);
|
||||
/**
|
||||
* An optional predicate function to determine if the test should run. If NULL, then the
|
||||
* test will only run once on the first attempt.
|
||||
|
@ -81,13 +88,15 @@ struct ztest_suite_node {
|
|||
* @param state The current state of the test application.
|
||||
* @return True if the suite should be run; false to skip.
|
||||
*/
|
||||
bool (*predicate)(const void *state);
|
||||
bool (*const predicate)(const void *state);
|
||||
/** Stats */
|
||||
struct ztest_suite_stats stats;
|
||||
struct ztest_suite_stats * const stats;
|
||||
};
|
||||
|
||||
extern struct ztest_suite_node _ztest_suite_node_list_start[];
|
||||
extern struct ztest_suite_node _ztest_suite_node_list_end[];
|
||||
#define ZTEST_SUITE_COUNT (_ztest_suite_node_list_end - _ztest_suite_node_list_start)
|
||||
|
||||
|
||||
/**
|
||||
* Create and register a ztest suite. Using this macro creates a new test suite (using
|
||||
|
@ -103,24 +112,27 @@ extern struct ztest_suite_node _ztest_suite_node_list_end[];
|
|||
* @param after_fn The function to call after each unit test in this suite
|
||||
* @param teardown_fn The function to call after running all the tests in this suite
|
||||
*/
|
||||
#define ZTEST_SUITE(SUITE_NAME, PREDICATE, setup_fn, before_fn, after_fn, teardown_fn) \
|
||||
static STRUCT_SECTION_ITERABLE(ztest_suite_node, \
|
||||
UTIL_CAT(z_ztest_test_node_, SUITE_NAME)) = { \
|
||||
.name = STRINGIFY(SUITE_NAME), \
|
||||
.setup = (setup_fn), \
|
||||
.before = (before_fn), \
|
||||
.after = (after_fn), \
|
||||
.teardown = (teardown_fn), \
|
||||
.predicate = PREDICATE, \
|
||||
#define ZTEST_SUITE(SUITE_NAME, PREDICATE, setup_fn, before_fn, after_fn, teardown_fn) \
|
||||
struct ztest_suite_stats UTIL_CAT(z_ztest_test_node_stats_, SUITE_NAME); \
|
||||
static const STRUCT_SECTION_ITERABLE(ztest_suite_node, \
|
||||
UTIL_CAT(z_ztest_test_node_, SUITE_NAME)) = { \
|
||||
.name = STRINGIFY(SUITE_NAME), \
|
||||
.setup = (setup_fn), \
|
||||
.before = (before_fn), \
|
||||
.after = (after_fn), \
|
||||
.teardown = (teardown_fn), \
|
||||
.predicate = PREDICATE, \
|
||||
.stats = &UTIL_CAT(z_ztest_test_node_stats_, SUITE_NAME), \
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the registered unit tests which return true from their pragma function.
|
||||
*
|
||||
* @param state The current state of the machine as it relates to the test executable.
|
||||
* @return The number of tests that ran.
|
||||
*/
|
||||
int ztest_run_test_suites(const void *state);
|
||||
__syscall int ztest_run_test_suites(const void *state);
|
||||
|
||||
#include <syscalls/ztest_test_new.h>
|
||||
|
||||
/**
|
||||
* @brief Fails the test if any of the registered tests did not run.
|
||||
|
@ -240,7 +252,7 @@ static inline void unit_test_noop(void)
|
|||
* @param suite The name of the test suite to attach this test
|
||||
* @param fn The test function to call.
|
||||
*/
|
||||
#define ZTEST_USER(suite, fn) Z_ZTEST(suite, fn, COND_CODE_1(CONFIG_USERSPACE, (K_USER), (0)))
|
||||
#define ZTEST_USER(suite, fn) Z_ZTEST(suite, fn, K_USER)
|
||||
|
||||
/**
|
||||
* @brief Define a test function
|
||||
|
@ -262,7 +274,7 @@ static inline void unit_test_noop(void)
|
|||
* @param suite The name of the test suite to attach this test
|
||||
* @param fn The test function to call.
|
||||
*/
|
||||
#define ZTEST_USER_F(suite, fn) Z_ZTEST_F(suite, fn, COND_CODE_1(CONFIG_USERSPACE, (K_USER), (0)))
|
||||
#define ZTEST_USER_F(suite, fn) Z_ZTEST_F(suite, fn, K_USER)
|
||||
|
||||
/**
|
||||
* @brief Test rule callback function signature
|
||||
|
@ -352,4 +364,6 @@ extern struct k_mem_partition ztest_mem_partition;
|
|||
}
|
||||
#endif
|
||||
|
||||
#include <syscalls/ztest_test_new.h>
|
||||
|
||||
#endif /* ZEPHYR_TESTSUITE_ZTEST_TEST_H_ */
|
||||
|
|
|
@ -381,6 +381,7 @@ static int run_test(struct unit_test *test)
|
|||
test->thread_options | K_INHERIT_PERMS,
|
||||
K_FOREVER);
|
||||
|
||||
k_thread_access_grant(&ztest_thread, test);
|
||||
if (test->name != NULL) {
|
||||
k_thread_name_set(&ztest_thread, test->name);
|
||||
}
|
||||
|
@ -468,7 +469,7 @@ int ztest_run_registered_test_suites(const void *state)
|
|||
int count = 0;
|
||||
|
||||
for (ptr = _ztest_suite_node_list_start; ptr < _ztest_suite_node_list_end; ++ptr) {
|
||||
struct ztest_suite_stats *stats = &ptr->stats;
|
||||
struct ztest_suite_stats *stats = ptr->stats;
|
||||
bool should_run = true;
|
||||
|
||||
if (ptr->predicate != NULL) {
|
||||
|
@ -498,7 +499,7 @@ void ztest_verify_all_registered_test_suites_ran(void)
|
|||
struct ztest_suite_node *ptr;
|
||||
|
||||
for (ptr = _ztest_suite_node_list_start; ptr < _ztest_suite_node_list_end; ++ptr) {
|
||||
if (ptr->stats.run_count < 1) {
|
||||
if (ptr->stats->run_count < 1) {
|
||||
PRINT("ERROR: Test '%s' did not run.\n", ptr->name);
|
||||
all_tests_run = false;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
|
||||
#include <ztest.h>
|
||||
#include <stdio.h>
|
||||
#include <zephyr/app_memory/app_memdomain.h>
|
||||
#ifdef CONFIG_USERSPACE
|
||||
#include <zephyr/sys/libc-hooks.h>
|
||||
|
@ -434,6 +433,7 @@ static int run_test(struct ztest_suite_node *suite, struct ztest_unit_test *test
|
|||
CONFIG_ZTEST_THREAD_PRIORITY,
|
||||
test->thread_options | K_INHERIT_PERMS, K_FOREVER);
|
||||
|
||||
k_thread_access_grant(&ztest_thread, suite, test, suite->stats);
|
||||
if (test->name != NULL) {
|
||||
k_thread_name_set(&ztest_thread, test->name);
|
||||
}
|
||||
|
@ -507,20 +507,20 @@ struct ztest_unit_test *ztest_get_next_test(const char *suite, struct ztest_unit
|
|||
}
|
||||
|
||||
#ifdef CONFIG_ZTEST_SHUFFLE
|
||||
static void z_ztest_shuffle(void *array, size_t num_items, void *tmp, size_t elem_size)
|
||||
static void z_ztest_shuffle(void *dest[], intptr_t start, size_t num_items, size_t element_size)
|
||||
{
|
||||
char *arr = array;
|
||||
for (size_t i = 0; i < num_items; ++i) {
|
||||
int pos = sys_rand32_get() % num_items;
|
||||
const int start_pos = pos;
|
||||
|
||||
for (int i = num_items - 1; i > 0; i--) {
|
||||
int j = sys_rand32_get() % (i + 1);
|
||||
|
||||
if (i != j) {
|
||||
memcpy(tmp, arr + (j * elem_size), elem_size);
|
||||
memcpy(arr + (j * elem_size), arr + (i * elem_size), elem_size);
|
||||
memcpy(arr + (i * elem_size), tmp, elem_size);
|
||||
/* Get the next valid position */
|
||||
while (dest[pos] != NULL) {
|
||||
pos = (pos + 1) % num_items;
|
||||
__ASSERT_NO_MSG(pos != start_pos);
|
||||
}
|
||||
}
|
||||
|
||||
dest[pos] = (void *)(start + (i * element_size));
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_ZTEST_SHUFFLE */
|
||||
|
||||
|
@ -530,10 +530,6 @@ static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite)
|
|||
void *data = NULL;
|
||||
int fail = 0;
|
||||
|
||||
#ifdef CONFIG_ZTEST_SHUFFLE
|
||||
struct ztest_unit_test tmp;
|
||||
#endif
|
||||
|
||||
if (test_status < 0) {
|
||||
return test_status;
|
||||
}
|
||||
|
@ -555,11 +551,24 @@ static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite)
|
|||
fail = 0;
|
||||
|
||||
#ifdef CONFIG_ZTEST_SHUFFLE
|
||||
z_ztest_shuffle(_ztest_unit_test_list_start,
|
||||
_ztest_unit_test_list_end - _ztest_unit_test_list_start, &tmp,
|
||||
sizeof(struct ztest_unit_test));
|
||||
#endif
|
||||
struct ztest_unit_test *tests_to_run[ZTEST_TEST_COUNT];
|
||||
|
||||
memset(tests_to_run, 0, ZTEST_TEST_COUNT * sizeof(struct ztest_unit_test *));
|
||||
z_ztest_shuffle((void **)tests_to_run, (intptr_t)_ztest_unit_test_list_start,
|
||||
ZTEST_TEST_COUNT, sizeof(struct ztest_unit_test));
|
||||
for (size_t i = 0; i < ZTEST_TEST_COUNT; ++i) {
|
||||
test = tests_to_run[i];
|
||||
/* Make sure that the test belongs to this suite */
|
||||
if (strcmp(suite->name, test->test_suite_name) != 0) {
|
||||
continue;
|
||||
}
|
||||
fail += run_test(suite, test, data);
|
||||
|
||||
if (fail && FAIL_FAST) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
while (((test = ztest_get_next_test(suite->name, test)) != NULL)) {
|
||||
fail += run_test(suite, test, data);
|
||||
|
||||
|
@ -567,6 +576,7 @@ static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite)
|
|||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
test_status = (test_status || fail) ? 1 : 0;
|
||||
}
|
||||
|
@ -598,42 +608,53 @@ void end_report(void)
|
|||
K_APPMEM_PARTITION_DEFINE(ztest_mem_partition);
|
||||
#endif
|
||||
|
||||
int ztest_run_test_suites(const void *state)
|
||||
static int __ztest_run_test_suite(struct ztest_suite_node *ptr, const void *state)
|
||||
{
|
||||
struct ztest_suite_stats *stats = ptr->stats;
|
||||
bool should_run = true;
|
||||
int count = 0;
|
||||
|
||||
if (ptr->predicate != NULL) {
|
||||
should_run = ptr->predicate(state);
|
||||
} else {
|
||||
/* If predicate is NULL, only run this test once. */
|
||||
should_run = stats->run_count == 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_ITER_PER_SUITE; i++) {
|
||||
if (should_run) {
|
||||
int fail = z_ztest_run_test_suite_ptr(ptr);
|
||||
|
||||
count++;
|
||||
stats->run_count++;
|
||||
stats->fail_count += (fail != 0) ? 1 : 0;
|
||||
} else {
|
||||
stats->skip_count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int z_impl_ztest_run_test_suites(const void *state)
|
||||
{
|
||||
struct ztest_suite_node *ptr;
|
||||
int count = 0;
|
||||
|
||||
#ifdef CONFIG_ZTEST_SHUFFLE
|
||||
struct ztest_suite_node tmp;
|
||||
struct ztest_suite_node *suites_to_run[ZTEST_SUITE_COUNT];
|
||||
|
||||
z_ztest_shuffle(_ztest_suite_node_list_start,
|
||||
_ztest_suite_node_list_end - _ztest_suite_node_list_start, &tmp,
|
||||
sizeof(struct ztest_suite_node));
|
||||
#endif
|
||||
|
||||
for (ptr = _ztest_suite_node_list_start; ptr < _ztest_suite_node_list_end; ++ptr) {
|
||||
struct ztest_suite_stats *stats = &ptr->stats;
|
||||
bool should_run = true;
|
||||
|
||||
if (ptr->predicate != NULL) {
|
||||
should_run = ptr->predicate(state);
|
||||
} else {
|
||||
/* If predicate is NULL, only run this test once. */
|
||||
should_run = stats->run_count == 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_ITER_PER_SUITE; i++) {
|
||||
if (should_run) {
|
||||
int fail = z_ztest_run_test_suite_ptr(ptr);
|
||||
|
||||
count++;
|
||||
stats->run_count++;
|
||||
stats->fail_count += (fail != 0) ? 1 : 0;
|
||||
} else {
|
||||
stats->skip_count++;
|
||||
}
|
||||
}
|
||||
memset(suites_to_run, 0, ZTEST_SUITE_COUNT * sizeof(struct ztest_suite_node *));
|
||||
z_ztest_shuffle((void **)suites_to_run, (intptr_t)_ztest_suite_node_list_start,
|
||||
ZTEST_SUITE_COUNT, sizeof(struct ztest_suite_node));
|
||||
for (size_t i = 0; i < ZTEST_SUITE_COUNT; ++i) {
|
||||
count += __ztest_run_test_suite(suites_to_run[i], state);
|
||||
}
|
||||
#else
|
||||
for (struct ztest_suite_node *ptr = _ztest_suite_node_list_start;
|
||||
ptr < _ztest_suite_node_list_end; ++ptr) {
|
||||
count += __ztest_run_test_suite(ptr, state);
|
||||
}
|
||||
#endif
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -645,7 +666,7 @@ void ztest_verify_all_test_suites_ran(void)
|
|||
struct ztest_unit_test *test;
|
||||
|
||||
for (suite = _ztest_suite_node_list_start; suite < _ztest_suite_node_list_end; ++suite) {
|
||||
if (suite->stats.run_count < 1) {
|
||||
if (suite->stats->run_count < 1) {
|
||||
PRINT("ERROR: Test suite '%s' did not run.\n", suite->name);
|
||||
all_tests_run = false;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue