Skip to content

Commit 47850a3

Browse files
asemjonovsnashif
authored andcommitted
ztest: Add config to shuffle test order
Enable ZTEST_DO_THE_SHUFFLE to shuffle the order tests are ran. Additional configs ZTEST_DO_THE_SHUFFLE_SUITE_REPEAT_COUNT ZTEST_DO_THE_SHUFFLE_TEST_REPEAT_COUNT specify the number of times the test or suite is executed. Signed-off-by: Al Semjonovs <[email protected]>
1 parent ce54efa commit 47850a3

File tree

6 files changed

+134
-14
lines changed

6 files changed

+134
-14
lines changed

doc/develop/test/twister.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,3 +750,12 @@ An example of entries in a quarantine yaml::
750750
platforms:
751751
- qemu_cortex_m3
752752
- native_posix
753+
754+
Running in Tests in Random Order
755+
********************************
756+
Enable ZTEST framework's :kconfig:option:`CONFIG_ZTEST_SHUFFLE` config option to
757+
run your tests in random order. This can be beneficial for identifying
758+
dependencies between test cases. For native_posix platforms, you can provide
759+
the seed to the random number generator by providing ``-seed=value`` as an
760+
argument to twister. See :ref:`Shuffling Test Sequence <ztest_shuffle>` for more
761+
details.

doc/develop/test/ztest.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,3 +508,17 @@ These will be surrounded by blocks such as::
508508
#ifndef SOMETHING
509509
#define SOMETHING <default implementation>
510510
#endif /* SOMETHING */
511+
512+
.. _ztest_shuffle:
513+
514+
Shuffling Test Sequence
515+
***********************
516+
By default the tests are sorted and ran in alphanumerical order. Test cases may
517+
be dependent on this sequence. Enable `ZTEST_SHUFFLE` to randomize the order. The
518+
output from the test will display the seed for failed tests. For native posix
519+
builds you can provide the seed as an argument to twister with `--seed`
520+
521+
Static configuration of ZTEST_SHUFFLE contains:
522+
523+
- :c:macro:`ZTEST_SHUFFLE_SUITE_REPEAT_COUNT` - Number of iterations the test suite will run.
524+
- :c:macro:`ZTEST_SHUFFLE_TEST_REPEAT_COUNT` - Number of iterations the test will run.

subsys/testsuite/ztest/Kconfig

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,30 @@ config ZTEST_RULE_1CPU
9797

9898
endmenu
9999

100+
config ZTEST_SHUFFLE
101+
bool "Shuffle the order of tests and suites"
102+
select TEST_RANDOM_GENERATOR if !ENTROPY_HAS_DRIVER
103+
help
104+
This rule will shuffle the order of tests and test suites.
105+
106+
if ZTEST_SHUFFLE
107+
config ZTEST_SHUFFLE_SUITE_REPEAT_COUNT
108+
int "Number of iterations the test suite will run"
109+
default 3
110+
help
111+
This rule will execute a test suite N number of times. The tests
112+
per suite will be shuffled on each iteration. The test order will likely
113+
be different per iteration.
114+
115+
config ZTEST_SHUFFLE_TEST_REPEAT_COUNT
116+
int "Number of iterations the test will run"
117+
default 3
118+
help
119+
This rule will execute a test N number of times. The test order will
120+
likely be different per iteration.
121+
122+
endif #ZTEST_SHUFFLE
123+
100124
endif # ZTEST_NEW_API
101125

102126
endif # ZTEST

subsys/testsuite/ztest/src/ztest_new.c

Lines changed: 68 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@ static struct k_thread ztest_thread;
2121
#include <unistd.h>
2222
#endif
2323

24+
#ifdef CONFIG_ZTEST_SHUFFLE
25+
#include <random/rand32.h>
26+
#include <stdlib.h>
27+
#include <time.h>
28+
#define NUM_ITER_PER_SUITE CONFIG_ZTEST_SHUFFLE_SUITE_REPEAT_COUNT
29+
#define NUM_ITER_PER_TEST CONFIG_ZTEST_SHUFFLE_TEST_REPEAT_COUNT
30+
#else
31+
#define NUM_ITER_PER_SUITE 1
32+
#define NUM_ITER_PER_TEST 1
33+
#endif
34+
2435
/* ZTEST_DMEM and ZTEST_BMEM are used for the application shared memory test */
2536

2637
/**
@@ -495,12 +506,34 @@ struct ztest_unit_test *ztest_get_next_test(const char *suite, struct ztest_unit
495506
return NULL;
496507
}
497508

509+
#ifdef CONFIG_ZTEST_SHUFFLE
510+
static void z_ztest_shuffle(void *array, size_t num_items, void *tmp, size_t elem_size)
511+
{
512+
char *arr = array;
513+
514+
for (int i = num_items - 1; i > 0; i--) {
515+
int j = sys_rand32_get() % (i + 1);
516+
517+
if (i != j) {
518+
memcpy(tmp, arr + (j * elem_size), elem_size);
519+
memcpy(arr + (j * elem_size), arr + (i * elem_size), elem_size);
520+
memcpy(arr + (i * elem_size), tmp, elem_size);
521+
}
522+
}
523+
524+
}
525+
#endif /* CONFIG_ZTEST_SHUFFLE */
526+
498527
static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite)
499528
{
500529
struct ztest_unit_test *test = NULL;
501530
void *data = NULL;
502531
int fail = 0;
503532

533+
#ifdef CONFIG_ZTEST_SHUFFLE
534+
struct ztest_unit_test tmp;
535+
#endif
536+
504537
if (test_status < 0) {
505538
return test_status;
506539
}
@@ -517,21 +550,33 @@ static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite)
517550
if (suite->setup != NULL) {
518551
data = suite->setup();
519552
}
520-
while ((test = ztest_get_next_test(suite->name, test)) != NULL) {
521-
fail += run_test(suite, test, data);
522553

523-
if (fail && FAIL_FAST) {
524-
break;
554+
for (int i = 0; i < NUM_ITER_PER_TEST; i++) {
555+
fail = 0;
556+
557+
#ifdef CONFIG_ZTEST_SHUFFLE
558+
z_ztest_shuffle(_ztest_unit_test_list_start,
559+
_ztest_unit_test_list_end - _ztest_unit_test_list_start, &tmp,
560+
sizeof(struct ztest_unit_test));
561+
#endif
562+
563+
while (((test = ztest_get_next_test(suite->name, test)) != NULL)) {
564+
fail += run_test(suite, test, data);
565+
566+
if (fail && FAIL_FAST) {
567+
break;
568+
}
525569
}
570+
571+
test_status = (test_status || fail) ? 1 : 0;
526572
}
573+
527574
TC_SUITE_END(suite->name, (fail > 0 ? TC_FAIL : TC_PASS));
528575
phase = TEST_PHASE_TEARDOWN;
529576
if (suite->teardown != NULL) {
530577
suite->teardown(data);
531578
}
532579

533-
test_status = (test_status || fail) ? 1 : 0;
534-
535580
return fail;
536581
}
537582

@@ -558,6 +603,14 @@ int ztest_run_test_suites(const void *state)
558603
struct ztest_suite_node *ptr;
559604
int count = 0;
560605

606+
#ifdef CONFIG_ZTEST_SHUFFLE
607+
struct ztest_suite_node tmp;
608+
609+
z_ztest_shuffle(_ztest_suite_node_list_start,
610+
_ztest_suite_node_list_end - _ztest_suite_node_list_start, &tmp,
611+
sizeof(struct ztest_suite_node));
612+
#endif
613+
561614
for (ptr = _ztest_suite_node_list_start; ptr < _ztest_suite_node_list_end; ++ptr) {
562615
struct ztest_suite_stats *stats = &ptr->stats;
563616
bool should_run = true;
@@ -569,14 +622,16 @@ int ztest_run_test_suites(const void *state)
569622
should_run = stats->run_count == 0;
570623
}
571624

572-
if (should_run) {
573-
int fail = z_ztest_run_test_suite_ptr(ptr);
625+
for (int i = 0; i < NUM_ITER_PER_SUITE; i++) {
626+
if (should_run) {
627+
int fail = z_ztest_run_test_suite_ptr(ptr);
574628

575-
count++;
576-
stats->run_count++;
577-
stats->fail_count += (fail != 0) ? 1 : 0;
578-
} else {
579-
stats->skip_count++;
629+
count++;
630+
stats->run_count++;
631+
stats->fail_count += (fail != 0) ? 1 : 0;
632+
} else {
633+
stats->skip_count++;
634+
}
580635
}
581636
}
582637

tests/ztest/base/prj_verbose_0.conf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
CONFIG_ZTEST=y
22
CONFIG_ZTEST_NEW_API=y
33
CONFIG_ZTEST_ASSERT_VERBOSE=0
4+
5+
CONFIG_ENTROPY_GENERATOR=y
6+
CONFIG_TEST_RANDOM_GENERATOR=y
7+
CONFIG_TIMER_RANDOM_GENERATOR=y
8+
9+
CONFIG_ZTEST_SHUFFLE=y
10+
CONFIG_ZTEST_SHUFFLE_SUITE_REPEAT_COUNT=2
11+
CONFIG_ZTEST_SHUFFLE_TEST_REPEAT_COUNT=2

tests/ztest/base/src/main.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ enum rule_state {
7676

7777
struct rules_tests_fixture {
7878
enum rule_state state;
79+
int run_count;
7980
};
8081

8182
static struct rules_tests_fixture rule_tests_fixture;
@@ -88,7 +89,11 @@ static void rule_before_each(const struct ztest_unit_test *test, void *data)
8889

8990
zassert_equal_ptr(&rule_tests_fixture, data,
9091
"Data expected to point to rule_state");
91-
zassert_equal(fixture->state, RULE_STATE_SETUP, "Unexpected state");
92+
if (fixture->run_count == 0) {
93+
zassert_equal(fixture->state, RULE_STATE_SETUP, "Unexpected state");
94+
} else {
95+
zassert_equal(fixture->state, RULE_STATE_AFTER_EACH, "Unexpected state");
96+
}
9297
fixture->state = RULE_STATE_BEFORE_EACH;
9398
}
9499
}
@@ -109,6 +114,7 @@ static void rule_after_each(const struct ztest_unit_test *test, void *data)
109114
static void *rule_test_setup(void)
110115
{
111116
rule_tests_fixture.state = RULE_STATE_SETUP;
117+
rule_tests_fixture.run_count = 0;
112118
return &rule_tests_fixture;
113119
}
114120

@@ -121,6 +127,9 @@ static void rule_test_teardown(void *data)
121127
* after_each function was called.
122128
*/
123129
zassert_equal(fixture->state, RULE_STATE_AFTER_EACH, "Unexpected state");
130+
#ifdef CONFIG_ZTEST_SHUFFLE
131+
zassert_equal(fixture->run_count, CONFIG_ZTEST_SHUFFLE_TEST_REPEAT_COUNT, NULL);
132+
#endif
124133
}
125134

126135
ZTEST_RULE(verify_before_after_rule, rule_before_each, rule_after_each);
@@ -131,4 +140,5 @@ ZTEST_F(rules_tests, test_rules_before_after)
131140
{
132141
zassert_equal(this->state, RULE_STATE_BEFORE_EACH, "Unexpected state");
133142
this->state = RULE_STATE_TEST;
143+
this->run_count++;
134144
}

0 commit comments

Comments
 (0)