Skip to content

Commit 4b0eeaf

Browse files
lemreyeivindj-nordic
authored andcommitted
tests: lib: bm_timer: add ztest suite
Add ztest for bm_timer running on hardware. Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
1 parent 9d4a2f7 commit 4b0eeaf

5 files changed

Lines changed: 252 additions & 0 deletions

File tree

CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@
103103
/sysbuild/ @nrfconnect/ncs-co-build-system
104104

105105
# Tests
106+
/tests/lib/ @nrfconnect/ncs-bm
106107
/tests/subsys/fs/bm_zms/ @nrfconnect/ncs-bm @rghaddab
107108
/tests/subsys/kmu/ @nrfconnect/ncs-eris @nrfconnect/ncs-eris-test
108109
/tests/unit/lib/ @nrfconnect/ncs-bm

tests/lib/bm_timer/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#
2+
# Copyright (c) 2026 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
cmake_minimum_required(VERSION 3.20.0)
8+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
9+
project(bm_timer_test)
10+
11+
target_sources(app PRIVATE src/main.c)

tests/lib/bm_timer/prj.conf

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#
2+
# Copyright (c) 2026 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
# Enable the ZTEST framework
8+
CONFIG_ZTEST=y
9+
10+
# Module under test
11+
CONFIG_BM_TIMER=y
12+
13+
# Logging for test output
14+
CONFIG_LOG=y

tests/lib/bm_timer/src/main.c

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/*
2+
* Copyright (c) 2026 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#include <errno.h>
8+
#include <stdint.h>
9+
#include <string.h>
10+
#include <zephyr/kernel.h>
11+
#include <zephyr/sys/atomic.h>
12+
#include <zephyr/ztest.h>
13+
14+
#include <bm/bm_timer.h>
15+
16+
/* Timer duration that is comfortably above BM_TIMER_MIN_TIMEOUT_TICKS but short enough
17+
* to keep the tests fast. ~50 ms is plenty for both single shot and repeated tests.
18+
*/
19+
#define TEST_TIMER_MS 50U
20+
#define TEST_TIMER_TICKS BM_TIMER_MS_TO_TICKS(TEST_TIMER_MS)
21+
22+
/* Slack to allow the timer to fire before the test thread checks the result. */
23+
#define TEST_TIMER_WAIT_MS (TEST_TIMER_MS + 50U)
24+
25+
/* Magic value used to verify the context pointer is forwarded to the handler. */
26+
#define TEST_CONTEXT_MAGIC ((void *)0xDEADBEEFUL)
27+
28+
/* Shared test state updated from the timer expiry handler (interrupt context). */
29+
static atomic_t handler_call_count;
30+
static void *last_context;
31+
32+
static void timeout_handler(void *context)
33+
{
34+
last_context = context;
35+
atomic_inc(&handler_call_count);
36+
}
37+
38+
static void reset_handler_state(void)
39+
{
40+
atomic_set(&handler_call_count, 0);
41+
last_context = NULL;
42+
}
43+
44+
static void before(void *fixture)
45+
{
46+
ARG_UNUSED(fixture);
47+
reset_handler_state();
48+
}
49+
50+
ZTEST(bm_timer, test_bm_timer_init_efault)
51+
{
52+
int err;
53+
struct bm_timer timer;
54+
55+
err = bm_timer_init(NULL, BM_TIMER_MODE_SINGLE_SHOT, timeout_handler);
56+
zassert_equal(err, -EFAULT, "expected -EFAULT for NULL timer, got %d", err);
57+
58+
err = bm_timer_init(&timer, BM_TIMER_MODE_SINGLE_SHOT, NULL);
59+
zassert_equal(err, -EFAULT, "expected -EFAULT for NULL handler, got %d", err);
60+
61+
err = bm_timer_init(NULL, BM_TIMER_MODE_REPEATED, NULL);
62+
zassert_equal(err, -EFAULT, "expected -EFAULT when both args are NULL, got %d", err);
63+
}
64+
65+
ZTEST(bm_timer, test_bm_timer_start_min_timeout_einval)
66+
{
67+
int err;
68+
struct bm_timer timer;
69+
70+
err = bm_timer_init(&timer, BM_TIMER_MODE_SINGLE_SHOT, timeout_handler);
71+
zassert_ok(err, "bm_timer_init failed, err %d", err);
72+
73+
err = bm_timer_start(&timer, 0, NULL);
74+
zassert_equal(err, -EINVAL, "expected -EINVAL for 0 ticks, got %d", err);
75+
76+
if (BM_TIMER_MIN_TIMEOUT_TICKS > 1U) {
77+
err = bm_timer_start(&timer, BM_TIMER_MIN_TIMEOUT_TICKS - 1U, NULL);
78+
zassert_equal(err, -EINVAL,
79+
"expected -EINVAL for ticks below min, got %d", err);
80+
}
81+
}
82+
83+
ZTEST(bm_timer, test_bm_timer_stop_efault)
84+
{
85+
int err;
86+
87+
err = bm_timer_stop(NULL);
88+
zassert_equal(err, -EFAULT, "expected -EFAULT for NULL timer, got %d", err);
89+
}
90+
91+
ZTEST(bm_timer, test_bm_timer_single_shot)
92+
{
93+
int err;
94+
struct bm_timer timer;
95+
96+
err = bm_timer_init(&timer, BM_TIMER_MODE_SINGLE_SHOT, timeout_handler);
97+
zassert_ok(err, "bm_timer_init failed, err %d", err);
98+
99+
err = bm_timer_start(&timer, TEST_TIMER_TICKS, NULL);
100+
zassert_ok(err, "bm_timer_start failed, err %d", err);
101+
102+
/* Wait long enough for the timer to expire at least three times if it
103+
* was incorrectly running in repeated mode.
104+
*/
105+
k_sleep(K_MSEC(TEST_TIMER_WAIT_MS * 3));
106+
107+
zassert_equal(atomic_get(&handler_call_count), 1,
108+
"single shot timer expired %ld times, expected 1",
109+
(long)atomic_get(&handler_call_count));
110+
}
111+
112+
ZTEST(bm_timer, test_bm_timer_repeated)
113+
{
114+
int err;
115+
struct bm_timer timer;
116+
atomic_val_t count;
117+
118+
err = bm_timer_init(&timer, BM_TIMER_MODE_REPEATED, timeout_handler);
119+
zassert_ok(err, "bm_timer_init failed, err %d", err);
120+
121+
err = bm_timer_start(&timer, TEST_TIMER_TICKS, NULL);
122+
zassert_ok(err, "bm_timer_start failed, err %d", err);
123+
124+
/* Wait long enough for the repeated timer to fire at least 3 times. */
125+
k_sleep(K_MSEC(TEST_TIMER_MS * 3 + 50U));
126+
127+
err = bm_timer_stop(&timer);
128+
zassert_ok(err, "bm_timer_stop failed, err %d", err);
129+
130+
count = atomic_get(&handler_call_count);
131+
zassert_true(count >= 3,
132+
"repeated timer expired only %ld times, expected at least 3",
133+
(long)count);
134+
}
135+
136+
ZTEST(bm_timer, test_bm_timer_stop)
137+
{
138+
int err;
139+
struct bm_timer timer;
140+
atomic_val_t count_after_stop;
141+
142+
err = bm_timer_init(&timer, BM_TIMER_MODE_REPEATED, timeout_handler);
143+
zassert_ok(err, "bm_timer_init failed, err %d", err);
144+
145+
err = bm_timer_start(&timer, TEST_TIMER_TICKS, NULL);
146+
zassert_ok(err, "bm_timer_start failed, err %d", err);
147+
148+
/* Stop the timer well before it has a chance to expire. */
149+
err = bm_timer_stop(&timer);
150+
zassert_ok(err, "bm_timer_stop failed, err %d", err);
151+
152+
/* Sleep long enough that the timer would have fired multiple times if
153+
* stopping had failed.
154+
*/
155+
k_sleep(K_MSEC(TEST_TIMER_WAIT_MS * 3));
156+
count_after_stop = atomic_get(&handler_call_count);
157+
158+
zassert_equal(count_after_stop, 0,
159+
"timer fired %ld times after being stopped, expected 0",
160+
(long)count_after_stop);
161+
162+
/* Stopping an already stopped timer must still succeed. */
163+
err = bm_timer_stop(&timer);
164+
zassert_ok(err, "stopping an inactive timer failed, err %d", err);
165+
}
166+
167+
ZTEST(bm_timer, test_bm_timer_context)
168+
{
169+
int err;
170+
struct bm_timer timer;
171+
172+
err = bm_timer_init(&timer, BM_TIMER_MODE_SINGLE_SHOT, timeout_handler);
173+
zassert_ok(err, "bm_timer_init failed, err %d", err);
174+
175+
err = bm_timer_start(&timer, TEST_TIMER_TICKS, TEST_CONTEXT_MAGIC);
176+
zassert_ok(err, "bm_timer_start failed, err %d", err);
177+
178+
k_sleep(K_MSEC(TEST_TIMER_WAIT_MS));
179+
180+
zassert_equal(atomic_get(&handler_call_count), 1,
181+
"expected exactly one expiry, got %ld",
182+
(long)atomic_get(&handler_call_count));
183+
zassert_equal_ptr(last_context, TEST_CONTEXT_MAGIC,
184+
"context not propagated to handler");
185+
}
186+
187+
ZTEST(bm_timer, test_bm_timer_restart)
188+
{
189+
int err;
190+
struct bm_timer timer;
191+
atomic_val_t count;
192+
193+
err = bm_timer_init(&timer, BM_TIMER_MODE_SINGLE_SHOT, timeout_handler);
194+
zassert_ok(err, "bm_timer_init failed, err %d", err);
195+
196+
/* Start, then restart with a fresh duration before the first expiry. */
197+
err = bm_timer_start(&timer, TEST_TIMER_TICKS, NULL);
198+
zassert_ok(err, "first bm_timer_start failed, err %d", err);
199+
200+
err = bm_timer_start(&timer, TEST_TIMER_TICKS, TEST_CONTEXT_MAGIC);
201+
zassert_ok(err, "restart bm_timer_start failed, err %d", err);
202+
203+
k_sleep(K_MSEC(TEST_TIMER_WAIT_MS * 2));
204+
205+
count = atomic_get(&handler_call_count);
206+
zassert_equal(count, 1,
207+
"single-shot timer expired %ld times after restart, expected 1",
208+
(long)count);
209+
zassert_equal_ptr(last_context, TEST_CONTEXT_MAGIC,
210+
"context not propagated to handler");
211+
}
212+
213+
ZTEST_SUITE(bm_timer, NULL, NULL, before, NULL, NULL);

tests/lib/bm_timer/testcase.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
common:
2+
tags:
3+
- bm_timer
4+
platform_allow:
5+
- bm_nrf54l15dk/nrf54l15/cpuapp/s115_softdevice
6+
- bm_nrf54l15dk/nrf54l10/cpuapp/s115_softdevice
7+
- bm_nrf54l15dk/nrf54l05/cpuapp/s115_softdevice
8+
integration_platforms:
9+
- bm_nrf54l15dk/nrf54l15/cpuapp/s115_softdevice
10+
tests:
11+
tests.lib.bm_timer:
12+
tags:
13+
- bm_timer

0 commit comments

Comments
 (0)