STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_self_test.c
Go to the documentation of this file.
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5#include "self_test.h"
6
7#define CHECK(condition) \
8 do { \
9 if (!(condition)) { \
10 fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, #condition); \
11 exit(1); \
12 } \
13 } while (0)
14
15typedef struct {
19 uint16_t call_order[64];
20 unsigned total_probes;
21 unsigned battery_calls;
27 uint32_t expected_budget;
29} fake_t;
30
31static self_test_reply_t probe(void* context, uint16_t id, uint8_t attempt,
32 uint32_t now_ms, uint32_t budget_ms) {
33 fake_t* f = context;
34 (void)now_ms;
35 CHECK(id >= 10 && id < 10 + SELF_TEST_MAX_DEVICES);
36 CHECK(budget_ms > 0 && budget_ms <= f->expected_budget);
37 f->last_probe_budget = budget_ms;
38 CHECK(f->total_probes < 64);
39 f->call_order[f->total_probes++] = id;
40 ++f->calls[id - 10];
41 f->attempts[id - 10] = attempt;
42 return f->replies[id - 10];
43}
44
45static self_test_battery_t battery(void* context, uint32_t now_ms,
46 uint32_t budget_ms) {
47 fake_t* f = context;
48 CHECK(budget_ms == f->expected_budget);
49 ++f->battery_calls;
51 if (f->fresh_battery) {
52 result.sampled_at_ms = now_ms;
53 }
54 return result;
55}
56
57static self_test_reply_t publish_status(void* context,
58 const self_test_status_t* status,
59 uint32_t budget_ms) {
60 fake_t* f = context;
61 CHECK(budget_ms == f->expected_budget);
63 f->sent = *status;
64 return f->publication;
65}
66
68
70 return (self_test_config_t){.device_count = 2,
71 .devices = {{10, true}, {11, true}},
72 .probe_timeout_ms = 100,
73 .retry_interval_ms = 20,
74 .heartbeat_interval_ms = 1000,
75 .battery_interval_ms = 200,
76 .battery_max_age_ms = 300,
77 .callback_budget_ms = 1,
78 .tick_budget_ms = 3,
79 .probe_max_attempts = 2,
80 .publication_max_attempts = 2};
81}
82
83static void setup(self_test_t* t, fake_t* f, const self_test_config_t* c,
84 uint32_t now) {
85 memset(f, 0, sizeof(*f));
86 for (unsigned i = 0; i < SELF_TEST_MAX_DEVICES; ++i) {
88 }
90 .reply = {SELF_TEST_PASS, 0}, .valid = true, .raw_counts = 32768};
91 f->fresh_battery = true;
94 CHECK(self_test_init(t, c, &port, f, now));
95}
96
97static void test_pass_and_inventory(void) {
98 self_test_t t = {0};
99 fake_t f;
101 setup(&t, &f, &c, 0);
102 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_PENDING);
103 CHECK(!self_test_status(&t)->battery.valid);
104 self_test_tick(&t, 0);
105 CHECK(f.total_probes == 1 && f.call_order[0] == 10);
106 CHECK(f.sent.probes_outcome == SELF_TEST_PENDING);
107 self_test_tick(&t, 1);
108 CHECK(f.total_probes == 2 && f.call_order[1] == 11);
109 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_PASS);
110 CHECK(f.calls[2] == 0 && f.attempts[0] == 1);
111 self_test_tick(&t, 1000);
112 CHECK(f.total_probes == 2);
113 CHECK(f.sent.probes_outcome == SELF_TEST_PASS);
114 CHECK(f.sent.devices[0].device_id == 10 && f.sent.devices[0].complete);
115 CHECK(f.sent.battery.valid && f.sent.battery.raw_counts == 32768);
116}
117
118static void test_terminal_results(void) {
122 for (unsigned i = 0; i < sizeof(results) / sizeof(results[0]); ++i) {
123 self_test_t t = {0};
124 fake_t f;
126 c.probe_max_attempts = 1;
127 setup(&t, &f, &c, 0);
128 f.replies[0] = (self_test_reply_t){results[i], 42};
129 self_test_tick(&t, 0);
130 self_test_tick(&t, 1);
131 self_test_tick(&t, 1000);
132 CHECK(f.sent.probes_outcome == SELF_TEST_FAIL);
133 CHECK(f.sent.devices[0].reply.result == results[i]);
134 CHECK(f.sent.devices[0].reply.diagnostic == 42);
135 CHECK(f.sent.devices[1].reply.result == SELF_TEST_PASS);
136 CHECK(f.calls[0] == 1 && f.calls[1] == 1);
137 CHECK(f.publication_calls == 2);
138 }
139}
140
142 self_test_t t = {0};
143 fake_t f;
146 c.probe_max_attempts = 1;
147 setup(&t, &f, &c, 0);
149 self_test_tick(&t, 0);
150 self_test_tick(&t, 1);
151 CHECK(f.calls[1] == 1);
152 self_test_tick(&t, 50);
153 CHECK(f.publication_calls == 2);
154 self_test_tick(&t, 99);
156 unsigned calls = f.calls[0];
157 self_test_tick(&t, 100);
158 CHECK(f.calls[0] == calls);
160 CHECK(self_test_status(&t)->devices[0].reply.diagnostic == 77);
161 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_FAIL);
162 CHECK(f.publication_calls == 3);
163}
164
166 self_test_t t = {0};
167 fake_t f;
169 c.device_count = 1;
170 setup(&t, &f, &c, 0);
172 self_test_tick(&t, 0);
173 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_PENDING);
174 self_test_tick(&t, 19);
175 CHECK(f.calls[0] == 1);
176 self_test_tick(&t, 20);
177 CHECK(f.calls[0] == 2 && f.attempts[0] == 2);
178 self_test_tick(&t, 1000);
179 CHECK(f.calls[0] == 2);
180 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_FAIL);
181 CHECK(self_test_reset(&t, 1001));
182 self_test_tick(&t, 1001);
184 self_test_tick(&t, 1021);
185 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_PASS);
186 CHECK(f.attempts[0] == 2);
187}
188
189static void test_timeout_retry(void) {
190 self_test_t t = {0};
191 fake_t f;
193 c.device_count = 1;
194 setup(&t, &f, &c, 0);
196 self_test_tick(&t, 0);
197 self_test_tick(&t, 100);
198 self_test_tick(&t, 119);
199 CHECK(f.calls[0] == 1);
200 self_test_tick(&t, 120);
201 CHECK(f.attempts[0] == 2);
202 self_test_tick(&t, 220);
203 CHECK(self_test_status(&t)->devices[0].complete);
205 self_test_tick(&t, 1000);
206 CHECK(f.calls[0] == 2);
207}
208
210 const uint32_t intervals[] = {500, 1000};
211 for (unsigned i = 0; i < 2; ++i) {
212 self_test_t t = {0};
213 fake_t f;
215 c.heartbeat_interval_ms = intervals[i];
216 setup(&t, &f, &c, 5);
217 CHECK(f.publication_calls == 0);
218 self_test_tick(&t, 10);
219 CHECK(f.publication_calls == 1);
220 self_test_tick(&t, 10 + intervals[i] - 1);
221 CHECK(f.publication_calls == 1);
222 self_test_tick(&t, 10 + intervals[i]);
223 CHECK(f.publication_calls == 2);
224 self_test_tick(&t, 11 + intervals[i]);
225 CHECK(f.publication_calls == 2);
226 self_test_tick(&t, 100000);
227 CHECK(f.publication_calls == 3);
228 self_test_tick(&t, 100000);
229 CHECK(f.publication_calls == 3);
230 self_test_tick(&t, 100000 + intervals[i]);
231 CHECK(f.publication_calls == 4);
232 }
233}
234
235static void test_wraparound(void) {
236 self_test_t t = {0};
237 fake_t f;
239 c.device_count = 1;
240 c.battery_interval_ms = 2000;
241 uint32_t start = UINT32_MAX - 50U;
242 setup(&t, &f, &c, start);
245 self_test_tick(&t, start + 99U);
247 self_test_tick(&t, start + 100U);
250 self_test_tick(&t, start + 120U);
251 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_PASS);
252 self_test_tick(&t, start + 299U);
253 CHECK(self_test_status(&t)->battery.valid);
254 self_test_tick(&t, start + 300U);
255 CHECK(!self_test_status(&t)->battery.valid);
256 self_test_tick(&t, start + 999U);
257 CHECK(f.publication_calls == 1);
258 self_test_tick(&t, start + 1000U);
259 CHECK(f.publication_calls == 2);
260}
261
262static void test_battery_validity(void) {
263 self_test_t t = {0};
264 fake_t f;
266 c.battery_interval_ms = 1000;
267 setup(&t, &f, &c, 0);
268 f.battery.raw_counts = 0;
269 self_test_tick(&t, 0);
270 CHECK(self_test_status(&t)->battery.valid);
271 self_test_tick(&t, 299);
272 CHECK(self_test_status(&t)->battery.valid);
273 self_test_tick(&t, 300);
274 CHECK(!self_test_status(&t)->battery.valid);
275 CHECK(self_test_status(&t)->battery.reply.diagnostic ==
277 f.battery.raw_counts = 65535;
278 self_test_tick(&t, 1000);
279 CHECK(f.sent.battery.valid && f.sent.battery.raw_counts == 65535);
281 self_test_tick(&t, 2000);
282 CHECK(!f.sent.battery.valid && f.sent.battery.raw_counts == 0);
283 CHECK(f.sent.battery.reply.diagnostic == 45);
285 f.fresh_battery = false;
286 f.battery.sampled_at_ms = 2999;
287 self_test_tick(&t, 4000);
288 CHECK(!f.sent.battery.valid);
289 f.battery.sampled_at_ms = 5001;
290 self_test_tick(&t, 5000);
291 CHECK(!f.sent.battery.valid);
292 f.fresh_battery = true;
293 f.battery.valid = false;
294 self_test_tick(&t, 6000);
295 CHECK(f.sent.battery.reply.diagnostic == SELF_TEST_DIAG_BAD_REPLY);
296 f.battery.valid = true;
297 self_test_tick(&t, 7000);
298 CHECK(f.sent.battery.valid);
299}
300
302 self_test_t t = {0};
303 fake_t f;
305 setup(&t, &f, &c, 0);
307 self_test_tick(&t, 0);
308 self_test_tick(&t, 19);
309 CHECK(f.publication_calls == 1);
310 CHECK(self_test_status(&t)->publication.diagnostic == 81);
311 self_test_tick(&t, 20);
312 CHECK(f.publication_calls == 2);
313 CHECK(f.sent.publication.result == SELF_TEST_FAIL);
314 CHECK(f.sent.probes_outcome == SELF_TEST_PASS);
315 self_test_tick(&t, 999);
316 CHECK(f.publication_calls == 2);
318 self_test_tick(&t, 1000);
319 CHECK(f.publication_calls == 3);
320 CHECK(self_test_status(&t)->publication.result == SELF_TEST_PASS);
321 CHECK(self_test_status(&t)->publication_attempts == 1);
323 self_test_tick(&t, 2000);
324 CHECK(self_test_status(&t)->publication.result == SELF_TEST_PENDING);
325 self_test_tick(&t, 2020);
326 CHECK(self_test_status(&t)->publication.result == SELF_TEST_TIMEOUT);
327 self_test_tick(&t, 2040);
328 CHECK(f.publication_calls == 5);
329}
330
331static void test_missing_and_optional(void) {
332 self_test_t t = {0};
334 self_test_port_t empty = {0};
335 CHECK(self_test_init(&t, &c, &empty, NULL, 0));
336 self_test_tick(&t, 0);
337 CHECK(self_test_status(&t)->devices[0].reply.result ==
339 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_FAIL);
340 CHECK(!self_test_status(&t)->battery.valid);
341 CHECK(self_test_status(&t)->publication.result ==
343 c.device_count = 0;
344 CHECK(self_test_init(&t, &c, &empty, NULL, 0));
345 self_test_tick(&t, 0);
346 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_NOT_CONFIGURED);
347 fake_t f;
348 c = config();
349 c.devices[0].required = false;
350 setup(&t, &f, &c, 0);
352 self_test_tick(&t, 0);
353 self_test_tick(&t, 1);
354 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_PASS);
355 CHECK(self_test_status(&t)->devices[0].reply.result ==
357 c.devices[1].required = false;
358 setup(&t, &f, &c, 0);
359 self_test_tick(&t, 0);
360 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_NOT_CONFIGURED);
361}
362
364 self_test_t t = {0};
365 fake_t f;
367 setup(&t, &f, &c, 0);
368 self_test_tick(&t, 0);
369 self_test_tick(&t, 1);
370 c.device_count = 0;
371 CHECK(self_test_reset(&t, 10));
372 CHECK(self_test_status(&t)->device_count == 2);
373 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_PENDING);
374 CHECK(!self_test_status(&t)->battery.valid);
375 CHECK(self_test_status(&t)->publication_attempts == 0);
376 self_test_tick(&t, 10);
377 CHECK(f.calls[0] == 2 && f.attempts[0] == 1);
378 CHECK(f.publication_calls == 2 && f.battery_calls == 2);
379 self_test_port_t copy = port;
380 c = config();
381 CHECK(self_test_init(&t, &c, &copy, &f, 20));
382 copy.probe = NULL;
383 self_test_tick(&t, 20);
384 CHECK(f.calls[0] == 3);
385}
386
387static void test_invalid_inputs(void) {
388 self_test_t t = {0};
391 self_test_tick(&t, 0);
393 CHECK(!self_test_reset(&t, 0) && !self_test_reset(NULL, 0));
394 CHECK(!self_test_init(NULL, &c, &port, NULL, 0));
395 CHECK(!self_test_init(&t, NULL, &port, NULL, 0));
396 CHECK(!self_test_init(&t, &c, NULL, NULL, 0));
397 for (unsigned i = 0; i < 13; ++i) {
398 c = config();
399 switch (i) {
400 case 0:
402 break;
403 case 1:
405 break;
406 case 2:
407 c.probe_timeout_ms = 0;
408 break;
409 case 3:
410 c.retry_interval_ms = 0;
411 break;
412 case 4:
413 c.heartbeat_interval_ms = UINT32_MAX;
414 break;
415 case 5:
417 break;
418 case 6:
419 c.battery_max_age_ms = 0;
420 break;
421 case 7:
422 c.callback_budget_ms = 0;
423 break;
424 case 8:
425 c.tick_budget_ms = 2;
426 break;
427 case 9:
428 c.probe_max_attempts = 0;
429 break;
430 case 10:
432 break;
433 case 12:
434 c.session_timeout_ms = 30000;
435 break;
436 case 11:
437 c.callback_budget_ms = UINT32_MAX;
438 break;
439 }
440 CHECK(!self_test_init(&t, &c, &port, NULL, 0));
441 self_test_tick(&t, 0);
443 }
444}
445
447 self_test_t t = {0};
448 fake_t f;
450 c.probe_max_attempts = 1;
451 setup(&t, &f, &c, 0);
455 self_test_tick(&t, 0);
456 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_FAIL);
457 CHECK(self_test_status(&t)->devices[0].reply.diagnostic ==
459 CHECK(!self_test_status(&t)->battery.valid);
460 CHECK(self_test_status(&t)->publication.result == SELF_TEST_FAIL);
461 CHECK(self_test_status(&t)->publication.diagnostic ==
463}
464
465static void test_full_inventory_budget(void) {
466 self_test_t t = {0};
467 fake_t f;
470 for (uint8_t i = 0; i < c.device_count; ++i) {
471 c.devices[i] = (self_test_device_t){(uint16_t)(10 + i), true};
472 }
473 setup(&t, &f, &c, 0);
474 for (uint8_t i = 0; i < c.device_count; ++i) {
475 unsigned before =
477 self_test_tick(&t, i);
479 3);
480 CHECK(f.call_order[i] == 10 + i);
481 }
482 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_PASS);
483}
484
485static void test_session_deadline(void) {
486 const uint32_t starts[] = {0, UINT32_MAX - 20U};
487 for (unsigned n = 0; n < 2; ++n) {
488 self_test_t t = {0};
489 fake_t f;
491 c.session_timeout_ms = 50;
492 c.callback_budget_ms = 7;
493 c.tick_budget_ms = 21;
494 c.devices[1].required = false;
495 uint32_t start = starts[n];
496 setup(&t, &f, &c, start);
499 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_PASS);
500 CHECK(!self_test_status(&t)->probes_complete);
501 self_test_tick(&t, start + 49U);
502 CHECK(f.last_probe_budget == 1);
503 CHECK(!self_test_status(&t)->deadline_expired);
504 unsigned calls = f.total_probes;
505 self_test_tick(&t, start + 50U);
506 const self_test_status_t* status = self_test_status(&t);
507 CHECK(status->probes_complete && status->deadline_expired);
508 CHECK(status->devices[0].reply.result == SELF_TEST_PASS);
509 CHECK(status->devices[1].reply.result == SELF_TEST_TIMEOUT);
510 CHECK(status->devices[1].reply.diagnostic ==
512 CHECK(status->devices[1].attempts == 1);
513 CHECK(status->probes_outcome == SELF_TEST_PASS);
514 self_test_tick(&t, start + 1000U);
515 CHECK(f.total_probes == calls);
516 CHECK(f.sent.probes_complete && f.sent.deadline_expired);
517 CHECK(self_test_reset(&t, start + 1001U));
518 CHECK(!self_test_status(&t)->probes_complete);
519 CHECK(!self_test_status(&t)->deadline_expired);
521 self_test_tick(&t, start + 1001U);
522 self_test_tick(&t, start + 1002U);
523 CHECK(self_test_status(&t)->probes_complete);
524 self_test_tick(&t, start + 2000U);
525 CHECK(!self_test_status(&t)->deadline_expired);
526 }
527}
528
530 self_test_t t = {0};
531 fake_t f;
533 c.session_timeout_ms = 20;
534 c.probe_max_attempts = 3;
535 setup(&t, &f, &c, 0);
537 self_test_tick(&t, 0);
538 CHECK(!self_test_status(&t)->probes_complete);
539 self_test_tick(&t, 20);
540 CHECK(f.total_probes == 1);
541 CHECK(self_test_status(&t)->probes_complete);
542 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_FAIL);
545 CHECK(self_test_status(&t)->devices[1].attempts == 0);
546 c.session_timeout_ms = 0;
547 setup(&t, &f, &c, 0);
548 self_test_tick(&t, 29000);
549 CHECK(f.total_probes == 0);
550 CHECK(self_test_status(&t)->probes_complete);
551 CHECK(self_test_status(&t)->deadline_expired);
552 c.device_count = 0;
553 setup(&t, &f, &c, 0);
554 CHECK(self_test_status(&t)->probes_complete);
555 self_test_tick(&t, 29000);
556 CHECK(!self_test_status(&t)->deadline_expired);
557}
558
560 self_test_t t = {0};
561 fake_t f;
563 c.device_count = 1;
564 c.probe_max_attempts = 3;
565 setup(&t, &f, &c, 0);
567 self_test_tick(&t, 0);
568 self_test_tick(&t, 20);
569 CHECK(!self_test_status(&t)->probes_complete);
570 self_test_tick(&t, 40);
571 CHECK(self_test_status(&t)->probes_complete);
572 CHECK(self_test_status(&t)->probes_outcome == SELF_TEST_FAIL);
573 CHECK(!self_test_status(&t)->deadline_expired);
574 CHECK(f.attempts[0] == 3);
575}
576
static board_spi_device_t devices[BOARD_SPI_COUNT]
Definition board_devbus.c:7
static emmc_status_t probe(emmc_log_t *log, uint32_t k, bool *valid, uint32_t *session)
Definition emmc_log.c:284
static const emmc_port_t port
Definition emmc_stm32.c:210
void setup()
Definition main.cpp:571
static void start(gnss_frame_parser_t *p, uint8_t byte)
Definition gnss_frame.c:45
#define NULL
Definition usbd_def.h:44
json_pointer result
Definition json.hpp:14064
*brief user defined string literal for JSON values *sa std::size_t n
Definition json.hpp:24474
bool self_test_init(self_test_t *t, const self_test_config_t *config, const self_test_port_t *port, void *context, uint32_t now_ms)
Definition self_test.c:98
void self_test_tick(self_test_t *t, uint32_t now_ms)
Definition self_test.c:244
bool self_test_reset(self_test_t *t, uint32_t now_ms)
Definition self_test.c:74
const self_test_status_t * self_test_status(const self_test_t *t)
Definition self_test.c:270
static self_test_reply_t reply(self_test_result_t result, int32_t diagnostic)
#define SELF_TEST_DIAG_BAD_REPLY
#define SELF_TEST_MAX_DEVICES
#define SELF_TEST_DIAG_STALE_BATTERY
#define SELF_TEST_DIAG_SESSION_TIMEOUT
self_test_result_t
@ SELF_TEST_FAIL
@ SELF_TEST_NOT_CONFIGURED
@ SELF_TEST_NOT_IMPLEMENTED
@ SELF_TEST_PENDING
@ SELF_TEST_PASS
@ SELF_TEST_TIMEOUT
unsigned publication_calls
bool fresh_battery
uint32_t last_probe_budget
self_test_battery_t battery
Definition test_idle.c:21
self_test_reply_t publication
uint32_t expected_budget
Definition test_idle.c:33
uint16_t call_order[64]
unsigned calls[SELF_TEST_MAX_DEVICES]
unsigned total_probes
unsigned battery_calls
Definition test_idle.c:27
uint8_t attempts[SELF_TEST_MAX_DEVICES]
idle_heartbeat_t sent
Definition test_idle.c:30
self_test_reply_t replies[SELF_TEST_MAX_DEVICES]
idle_battery_state_t battery
Definition idle_port.h:45
self_test_reply_t reply
uint32_t heartbeat_interval_ms
Definition self_test.h:22
uint32_t session_timeout_ms
Definition self_test.h:30
self_test_device_t devices[SELF_TEST_MAX_DEVICES]
Definition self_test.h:19
uint32_t callback_budget_ms
Definition self_test.h:25
uint32_t retry_interval_ms
Definition self_test.h:21
uint32_t battery_interval_ms
Definition self_test.h:23
uint32_t probe_timeout_ms
Definition self_test.h:20
uint8_t device_count
Definition self_test.h:18
uint8_t publication_max_attempts
Definition self_test.h:28
uint32_t battery_max_age_ms
Definition self_test.h:24
uint8_t probe_max_attempts
Definition self_test.h:27
uint32_t tick_budget_ms
Definition self_test.h:26
uint16_t device_id
Definition self_test.h:13
self_test_reply_t(* probe)(void *context, uint16_t device_id, uint8_t attempt, uint32_t now_ms, uint32_t budget_ms)
self_test_result_t result
int main()
static void test_pass_and_inventory(void)
static void test_reset_and_copied_dependencies(void)
static void test_pending_timeout_and_fairness(void)
static void test_full_inventory_budget(void)
static void test_failure_completes_after_three_attempts(void)
static self_test_battery_t battery(void *context, uint32_t now_ms, uint32_t budget_ms)
#define CHECK(condition)
static void test_invalid_inputs(void)
static void test_terminal_results(void)
static void test_publication_retry_and_recovery(void)
static void test_timeout_retry(void)
static void test_probe_retry_bounds_and_recovery(void)
static self_test_reply_t probe(void *context, uint16_t id, uint8_t attempt, uint32_t now_ms, uint32_t budget_ms)
static void test_wraparound(void)
static void test_heartbeat_boundaries_and_gap(void)
static void test_session_deadline(void)
static self_test_config_t config(void)
static void test_malformed_driver_results(void)
static self_test_reply_t publish_status(void *context, const self_test_status_t *status, uint32_t budget_ms)
static void test_deadline_retry_and_unstarted(void)
static void test_battery_validity(void)
static void test_missing_and_optional(void)