Skip to content

Commit 8fa68e9

Browse files
committed
testing/drivers: add watchdog notifier cmocka coverage
Add a focused watchdog-only cmocka registration and exercise notifier ordering, duplicate registration, repeated timeout delivery, unregister behavior, NULL data, and concurrent register/timeout/unregister activity. Signed-off-by: hanzhijian <hanzhijian@zepp.com> Assisted-by: OpenAI Codex
1 parent 9a2faa8 commit 8fa68e9

4 files changed

Lines changed: 170 additions & 39 deletions

File tree

testing/drivers/drivertest/CMakeLists.txt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,22 @@
2121
# ##############################################################################
2222

2323
if(CONFIG_TESTING_DRIVER_TEST)
24+
if(CONFIG_TESTING_DRIVER_TEST_WATCHDOG_ONLY)
25+
nuttx_add_application(
26+
NAME
27+
cmocka_driver_watchdog
28+
PRIORITY
29+
${CONFIG_TESTING_DRIVER_TEST_PRIORITY}
30+
STACKSIZE
31+
${CONFIG_TESTING_DRIVER_TEST_STACKSIZE}
32+
MODULE
33+
${CONFIG_TESTING_DRIVER_TEST}
34+
DEPENDS
35+
cmocka
36+
SRCS
37+
drivertest_watchdog.c)
38+
endif()
39+
else()
2440
if(CONFIG_TESTING_DRIVER_TEST_SIMPLE)
2541
nuttx_add_application(
2642
NAME
@@ -452,5 +468,4 @@ if(CONFIG_TESTING_DRIVER_TEST)
452468
SRCS
453469
drivertest_pm_runtime.c)
454470
endif()
455-
456471
endif()

testing/drivers/drivertest/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ config TESTING_DRIVER_TEST_SIMPLE
2424
bool "Enable cmocka driver simple test"
2525
default n
2626

27+
config TESTING_DRIVER_TEST_WATCHDOG_ONLY
28+
bool "Build only the watchdog notifier cmocka test"
29+
default n
30+
depends on WATCHDOG
31+
---help---
32+
Build only cmocka_driver_watchdog. This is useful for a minimal
33+
simulator validation configuration without unrelated driver tests.
34+
2735
config TESTING_ONESHOT_TEST
2836
bool "Enable cmocka oneshot test"
2937
default n

testing/drivers/drivertest/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ PRIORITY = $(CONFIG_TESTING_DRIVER_TEST_PRIORITY)
2626
STACKSIZE = $(CONFIG_TESTING_DRIVER_TEST_STACKSIZE)
2727
MODULE = $(CONFIG_TESTING_DRIVER_TEST)
2828

29+
ifeq ($(CONFIG_TESTING_DRIVER_TEST_WATCHDOG_ONLY),y)
30+
MAINSRC += drivertest_watchdog.c
31+
PROGNAME += cmocka_driver_watchdog
32+
else
33+
2934
ifneq ($(CONFIG_TESTING_DRIVER_TEST_SIMPLE),)
3035
MAINSRC += drivertest_simple.c
3136
PROGNAME += cmocka_driver_simple
@@ -158,4 +163,6 @@ MAINSRC += drivertest_pm_runtime.c
158163
PROGNAME += cmocka_driver_pm_runtime
159164
endif
160165

166+
endif
167+
161168
include $(APPDIR)/Application.mk

testing/drivers/drivertest/drivertest_watchdog.c

Lines changed: 139 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include <stdint.h>
4444
#include <cmocka.h>
4545
#include <time.h>
46+
#include <pthread.h>
4647

4748
#include <nuttx/arch.h>
4849
#include <nuttx/notifier.h>
@@ -58,6 +59,12 @@
5859
#define WDG_DEFAULT_TIMEOUT 2000
5960
#define WDG_DEFAULT_TESTCASE 0
6061
#define WDG_DEFAULT_DEVIATION 20
62+
#ifndef BOARDIOC_RESETCAUSE_SYS_CHIPPOR
63+
# define BOARDIOC_RESETCAUSE_SYS_CHIPPOR 0
64+
#endif
65+
#ifndef BOARDIOC_RESETCAUSE_SYS_RWDT
66+
# define BOARDIOC_RESETCAUSE_SYS_RWDT 0
67+
#endif
6168
#if defined(CONFIG_ARCH_ARMV7A) && defined(CONFIG_ARCH_HAVE_TRUSTZONE)
6269
#define WDG_COUNT_TESTCASE 3
6370
#else
@@ -89,6 +96,12 @@ struct wdg_state_s
8996
uint32_t deviation;
9097
int test_case;
9198
bool test_getstatus;
99+
#ifdef CONFIG_WATCHDOG_TIMEOUT_NOTIFIER
100+
unsigned int notifier_calls;
101+
unsigned long notifier_action[8];
102+
FAR void *notifier_data[8];
103+
int notifier_id[8];
104+
#endif
92105
};
93106

94107
static sem_t g_semaphore;
@@ -297,18 +310,10 @@ static int capture_callback(int irq, FAR void *context, FAR void *arg)
297310
struct watchdog_notifier_test_nb_s
298311
{
299312
struct notifier_block nb;
300-
int id;
301-
};
302-
303-
struct watchdog_notifier_test_ctx_s
304-
{
305-
unsigned int calls;
306-
unsigned long action[8];
307-
FAR void *data[8];
308-
int id[8];
313+
int id;
309314
};
310315

311-
static FAR struct watchdog_notifier_test_ctx_s *g_notifier_test_ctx;
316+
static FAR struct wdg_state_s *g_notifier_test_state;
312317

313318
static int watchdog_notifier_test_callback(FAR struct notifier_block *nb,
314319
unsigned long action,
@@ -317,18 +322,16 @@ static int watchdog_notifier_test_callback(FAR struct notifier_block *nb,
317322
FAR struct watchdog_notifier_test_nb_s *test_nb;
318323
unsigned int index;
319324

320-
test_nb = (FAR struct watchdog_notifier_test_nb_s *)
321-
((FAR char *)nb - offsetof(struct watchdog_notifier_test_nb_s,
322-
nb));
323-
index = g_notifier_test_ctx->calls;
325+
test_nb = container_of(nb, struct watchdog_notifier_test_nb_s, nb);
326+
index = g_notifier_test_state->notifier_calls;
324327
if (index < 8)
325328
{
326-
g_notifier_test_ctx->action[index] = action;
327-
g_notifier_test_ctx->data[index] = data;
328-
g_notifier_test_ctx->id[index] = test_nb->id;
329+
g_notifier_test_state->notifier_action[index] = action;
330+
g_notifier_test_state->notifier_data[index] = data;
331+
g_notifier_test_state->notifier_id[index] = test_nb->id;
329332
}
330333

331-
g_notifier_test_ctx->calls++;
334+
g_notifier_test_state->notifier_calls++;
332335
return OK;
333336
}
334337

@@ -353,10 +356,7 @@ static unsigned long watchdog_notifier_test_expected_action(void)
353356

354357
static void drivertest_watchdog_notifier(FAR void **state)
355358
{
356-
struct watchdog_notifier_test_ctx_s context =
357-
{
358-
0
359-
};
359+
FAR struct wdg_state_s *wdg_state = *state;
360360

361361
struct watchdog_notifier_test_nb_s low =
362362
{
@@ -382,7 +382,8 @@ static void drivertest_watchdog_notifier(FAR void **state)
382382

383383
UNUSED(state);
384384
expected_action = watchdog_notifier_test_expected_action();
385-
g_notifier_test_ctx = &context;
385+
wdg_state->notifier_calls = 0;
386+
g_notifier_test_state = wdg_state;
386387

387388
/* Registration is priority ordered, and duplicate registration of the
388389
* same notifier must not result in a duplicate callback.
@@ -394,35 +395,116 @@ static void drivertest_watchdog_notifier(FAR void **state)
394395

395396
watchdog_automonitor_timeout();
396397

397-
assert_int_equal(context.calls, 2);
398-
assert_int_equal(context.id[0], high.id);
399-
assert_int_equal(context.id[1], low.id);
400-
assert_int_equal(context.action[0], expected_action);
401-
assert_int_equal(context.action[1], expected_action);
402-
assert_null(context.data[0]);
403-
assert_null(context.data[1]);
398+
assert_int_equal(wdg_state->notifier_calls, 2);
399+
assert_int_equal(wdg_state->notifier_id[0], high.id);
400+
assert_int_equal(wdg_state->notifier_id[1], low.id);
401+
assert_int_equal(wdg_state->notifier_action[0], expected_action);
402+
assert_int_equal(wdg_state->notifier_action[1], expected_action);
403+
assert_null(wdg_state->notifier_data[0]);
404+
assert_null(wdg_state->notifier_data[1]);
404405

405406
/* Every timeout notification is delivered to all currently registered
406407
* callbacks.
407408
*/
408409

409410
watchdog_automonitor_timeout();
410-
assert_int_equal(context.calls, 4);
411-
assert_int_equal(context.id[2], high.id);
412-
assert_int_equal(context.id[3], low.id);
411+
assert_int_equal(wdg_state->notifier_calls, 4);
412+
assert_int_equal(wdg_state->notifier_id[2], high.id);
413+
assert_int_equal(wdg_state->notifier_id[3], low.id);
413414

414415
/* Unregistering one callback removes only that callback. */
415416

416417
watchdog_notifier_chain_unregister(&high.nb);
417418
watchdog_automonitor_timeout();
418-
assert_int_equal(context.calls, 5);
419-
assert_int_equal(context.id[4], low.id);
419+
assert_int_equal(wdg_state->notifier_calls, 5);
420+
assert_int_equal(wdg_state->notifier_id[4], low.id);
420421

421422
watchdog_notifier_chain_unregister(&low.nb);
422423
watchdog_automonitor_timeout();
423-
assert_int_equal(context.calls, 5);
424+
assert_int_equal(wdg_state->notifier_calls, 5);
425+
426+
g_notifier_test_state = NULL;
427+
}
428+
429+
struct watchdog_notifier_race_s
430+
{
431+
struct watchdog_notifier_test_nb_s nb;
432+
volatile bool stop;
433+
};
434+
435+
static volatile unsigned int g_notifier_race_callbacks;
436+
437+
static int watchdog_notifier_race_callback(FAR struct notifier_block *nb,
438+
unsigned long action,
439+
FAR void *data)
440+
{
441+
UNUSED(nb);
442+
UNUSED(action);
443+
UNUSED(data);
444+
g_notifier_race_callbacks++;
445+
return OK;
446+
}
447+
448+
static FAR void *watchdog_notifier_race_worker(FAR void *arg)
449+
{
450+
FAR struct watchdog_notifier_race_s *race = arg;
451+
unsigned int count;
452+
453+
for (count = 0; count < 2000 && !race->stop; count++)
454+
{
455+
watchdog_notifier_chain_register(&race->nb.nb);
456+
watchdog_automonitor_timeout();
457+
watchdog_notifier_chain_unregister(&race->nb.nb);
458+
}
424459

425-
g_notifier_test_ctx = NULL;
460+
return NULL;
461+
}
462+
463+
static void drivertest_watchdog_notifier_race(FAR void **state)
464+
{
465+
struct watchdog_notifier_race_s race =
466+
{
467+
.nb =
468+
{
469+
.nb =
470+
{
471+
.notifier_call = watchdog_notifier_race_callback,
472+
.priority = 10
473+
},
474+
.id = 3
475+
}
476+
};
477+
478+
pthread_t thread;
479+
unsigned int count;
480+
int ret;
481+
482+
UNUSED(state);
483+
g_notifier_race_callbacks = 0;
484+
watchdog_notifier_chain_register(&race.nb.nb);
485+
ret = pthread_create(&thread, NULL, watchdog_notifier_race_worker, &race);
486+
assert_int_equal(ret, 0);
487+
usleep(1000);
488+
489+
/* Interleave timeout delivery with registration and unregistration from
490+
* another task. The test is successful if the notifier chain remains
491+
* usable and no callback observes a non-NULL payload.
492+
*/
493+
494+
for (count = 0; count < 2000; count++)
495+
{
496+
watchdog_automonitor_timeout();
497+
if ((count & 0x3f) == 0)
498+
{
499+
usleep(1000);
500+
}
501+
}
502+
503+
race.stop = true;
504+
ret = pthread_join(thread, NULL);
505+
assert_int_equal(ret, 0);
506+
watchdog_notifier_chain_unregister(&race.nb.nb);
507+
assert_true(g_notifier_race_callbacks > 0);
426508
}
427509

428510
#endif /* CONFIG_WATCHDOG_TIMEOUT_NOTIFIER */
@@ -441,7 +523,9 @@ static void drivertest_watchdog_feeding(FAR void **state)
441523
int ret;
442524
uint32_t start_ms;
443525
FAR struct wdg_state_s *wdg_state;
526+
#ifdef CONFIG_BOARDCTL_RESET_CAUSE
444527
struct boardioc_reset_cause_s reset_cause;
528+
#endif
445529

446530
wdg_state = (FAR struct wdg_state_s *)*state;
447531

@@ -452,8 +536,10 @@ static void drivertest_watchdog_feeding(FAR void **state)
452536
return;
453537
}
454538

539+
#ifdef CONFIG_BOARDCTL_RESET_CAUSE
455540
boardctl(BOARDIOC_RESET_CAUSE, (uintptr_t)&reset_cause);
456541
assert_int_equal(reset_cause.cause, BOARDIOC_RESETCAUSE_SYS_CHIPPOR);
542+
#endif
457543

458544
dev_fd = wdg_init(wdg_state);
459545

@@ -497,7 +583,9 @@ static void drivertest_watchdog_feeding(FAR void **state)
497583
static void drivertest_watchdog_interrupts(FAR void **state)
498584
{
499585
FAR struct wdg_state_s *wdg_state;
586+
#ifdef CONFIG_BOARDCTL_RESET_CAUSE
500587
struct boardioc_reset_cause_s reset_cause;
588+
#endif
501589

502590
wdg_state = (FAR struct wdg_state_s *)*state;
503591

@@ -506,8 +594,10 @@ static void drivertest_watchdog_interrupts(FAR void **state)
506594
return;
507595
}
508596

597+
#ifdef CONFIG_BOARDCTL_RESET_CAUSE
509598
boardctl(BOARDIOC_RESET_CAUSE, (uintptr_t)&reset_cause);
510599
assert_int_equal(reset_cause.cause, BOARDIOC_RESETCAUSE_SYS_RWDT);
600+
#endif
511601

512602
wdg_init(wdg_state);
513603

@@ -542,7 +632,9 @@ static void drivertest_watchdog_loop(FAR void **state)
542632
int ret;
543633
static struct wdog_s wdog;
544634
FAR struct wdg_state_s *wdg_state;
635+
#ifdef CONFIG_BOARDCTL_RESET_CAUSE
545636
struct boardioc_reset_cause_s reset_cause;
637+
#endif
546638

547639
wdg_state = (FAR struct wdg_state_s *)*state;
548640

@@ -551,8 +643,10 @@ static void drivertest_watchdog_loop(FAR void **state)
551643
return;
552644
}
553645

646+
#ifdef CONFIG_BOARDCTL_RESET_CAUSE
554647
boardctl(BOARDIOC_RESET_CAUSE, (uintptr_t)&reset_cause);
555648
assert_int_equal(reset_cause.cause, BOARDIOC_RESETCAUSE_SYS_RWDT);
649+
#endif
556650

557651
wdg_init(wdg_state);
558652

@@ -581,15 +675,19 @@ static void drivertest_watchdog_api(FAR void **state)
581675
uint32_t start_ms;
582676
FAR struct wdg_state_s *wdg_state;
583677
struct watchdog_status_s status;
678+
#ifdef CONFIG_BOARDCTL_RESET_CAUSE
584679
struct boardioc_reset_cause_s reset_cause;
680+
#endif
585681
struct watchdog_capture_s watchdog_capture;
586682

587683
wdg_state = (FAR struct wdg_state_s *)*state;
588684

589685
assert_int_equal(wdg_state->test_case, 3);
590686

687+
#ifdef CONFIG_BOARDCTL_RESET_CAUSE
591688
boardctl(BOARDIOC_RESET_CAUSE, (uintptr_t)&reset_cause);
592689
assert_int_equal(reset_cause.cause, BOARDIOC_RESETCAUSE_SYS_RWDT);
690+
#endif
593691

594692
dev_fd = wdg_init(wdg_state);
595693

@@ -681,14 +779,17 @@ int main(int argc, FAR char *argv[])
681779

682780
const struct CMUnitTest tests[] =
683781
{
782+
#ifndef CONFIG_TESTING_DRIVER_TEST_WATCHDOG_ONLY
684783
cmocka_unit_test_prestate(drivertest_watchdog_feeding, &wdg_state),
685784
cmocka_unit_test_prestate(drivertest_watchdog_interrupts, &wdg_state),
686785
cmocka_unit_test_prestate(drivertest_watchdog_loop, &wdg_state),
687786
#if !defined(CONFIG_ARCH_ARMV7A) || !defined(CONFIG_ARCH_HAVE_TRUSTZONE)
688787
cmocka_unit_test_prestate(drivertest_watchdog_api, &wdg_state),
689788
#endif
789+
#endif
690790
#ifdef CONFIG_WATCHDOG_TIMEOUT_NOTIFIER
691-
cmocka_unit_test_prestate(drivertest_watchdog_notifier, &wdg_state)
791+
cmocka_unit_test_prestate(drivertest_watchdog_notifier, &wdg_state),
792+
cmocka_unit_test_prestate(drivertest_watchdog_notifier_race, &wdg_state)
692793
#endif
693794
};
694795

0 commit comments

Comments
 (0)