The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
machine_tests.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Tests for the observable state machine
18 *
19 * @file src/lib/util/test/machine_tests.c
20 *
21 * @copyright 2026 Network RADIUS SAS (legal@networkradius.com)
22 */
23#include "acutest_common_init.h"
24#include "acutest_helpers.h"
25
26#include <freeradius-devel/util/machine.h>
27
28/*
29 * A machine shaped like the connection state machine.
30 */
39
47
48#define CONN_ROW(_from, ...) FR_MACHINE_ROW(conn_state_t, _from, __VA_ARGS__)
49
55 /* CONN_CLOSED is terminal */
56);
57
58FR_MACHINE_TYPES(conn, conn_state_t)
59FR_MACHINE_FUNCS(conn, conn_state_t)
60
61/*
62 * Every callback appends one line to the log, and the tests
63 * compare the log against the expected order.
64 */
65#define LOG_MAX 32
66static char const *event_log[LOG_MAX];
67static size_t event_num;
68static int enter_ret; /* returned by the CONNECTED entry function */
69
70static void log_reset(void)
71{
72 event_num = 0;
73 enter_ret = 0;
74}
75
76static void log_add(char const *event)
77{
79 event_log[event_num++] = event;
80}
81
83{
84 log_add("enter CONNECTED");
85 return enter_ret;
86}
87
89{
90 log_add("exit CONNECTING");
91}
92
94{
95 log_add("enter CONNECTING");
96 return 0;
97}
98
103
105 .name = "conn",
106 .state_names = conn_state_names,
107 .state_names_len = NUM_ELEMENTS(conn_state_names),
108 .valid = &conn_valid,
109 .states = conn_states
110};
111
112/*
113 * Watchers log their uctx, a string naming the registration.
114 */
115static void watch_log(UNUSED conn_machine_t *m, UNUSED conn_state_t prev, UNUSED conn_state_t state, void *uctx)
116{
117 log_add(uctx);
118}
119
120/*
121 * A watcher that requests a transition. uctx is the target.
122 */
123static void watch_transition(conn_machine_t *m, UNUSED conn_state_t prev, UNUSED conn_state_t state, void *uctx)
124{
125 conn_state_t to = *(conn_state_t *)uctx;
126
127 log_add("watch requests transition");
128 TEST_CHECK(conn_machine_transition(m, to) == FR_MACHINE_QUEUED);
129}
130
131static bool log_matches(char const * const expected[], size_t expected_num)
132{
133 size_t i;
134
135 TEST_CHECK(event_num == expected_num);
136 TEST_MSG("logged %zu events, expected %zu", event_num, expected_num);
137 if (event_num != expected_num) {
138 for (i = 0; i < event_num; i++) TEST_MSG(" logged[%zu] = %s", i, event_log[i]);
139 return false;
140 }
141
142 for (i = 0; i < expected_num; i++) {
143 TEST_CHECK(strcmp(event_log[i], expected[i]) == 0);
144 TEST_MSG("event %zu: logged \"%s\", expected \"%s\"", i, event_log[i], expected[i]);
145 }
146
147 return true;
148}
149#define LOG_MATCHES(...) \
150 log_matches((char const * const []){ __VA_ARGS__ }, VA_NARG(__VA_ARGS__))
151
152static void test_init(void)
153{
154 conn_machine_t m;
155
156 log_reset();
157 conn_machine_init(&m, &conn_def, CONN_INIT, NULL);
158
159 TEST_CASE("init sets the state and prev, and runs nothing");
160 TEST_CHECK(conn_machine_state(&m) == CONN_INIT);
161 TEST_CHECK(conn_machine_prev(&m) == CONN_INIT);
162 TEST_CHECK(event_num == 0);
163
164 TEST_CASE("state names resolve");
165 TEST_CHECK(strcmp(conn_machine_state_name(&m, CONN_CONNECTING), "CONN_CONNECTING") == 0);
166 TEST_CHECK(strcmp(fr_machine_state_name(&conn_def, FR_MACHINE_STATE_ANY), "<any>") == 0);
167 TEST_CHECK(strcmp(fr_machine_state_name(&conn_def, CONN_MAX), "<INVALID>") == 0);
168
169 conn_machine_fini(&m);
170}
171
172static void test_table(void)
173{
174 conn_machine_t m;
175
176 conn_machine_init(&m, &conn_def, CONN_INIT, NULL);
177
178 TEST_CASE("the table allows listed transitions");
179 TEST_CHECK(conn_machine_next_valid(&m, CONN_CONNECTING));
180 TEST_CHECK(conn_machine_next_valid(&m, CONN_CLOSED));
181
182 TEST_CASE("the table rejects unlisted transitions, self transitions and out of range states");
183 TEST_CHECK(!conn_machine_next_valid(&m, CONN_CONNECTED));
184 TEST_CHECK(!conn_machine_next_valid(&m, CONN_INIT));
185 TEST_CHECK(!conn_machine_next_valid(&m, CONN_MAX));
186
187 TEST_CASE("a terminal state has no exits");
188 m.m.state = CONN_CLOSED;
189 TEST_CHECK(!conn_machine_next_valid(&m, CONN_INIT));
190 TEST_CHECK(!conn_machine_next_valid(&m, CONN_CONNECTING));
191
192 conn_machine_fini(&m);
193}
194
195static void test_transition_order(void)
196{
197 TALLOC_CTX *ctx = talloc_init_const("test");
198 conn_machine_t m;
199
200 log_reset();
201 conn_machine_init(&m, &conn_def, CONN_INIT, NULL);
202 conn_machine_watch_add_any(&m, ctx, CONN_CONNECTED, FR_MACHINE_PRE_ENTER, watch_log, false, "pre CONNECTED");
203 conn_machine_watch_add_any(&m, ctx, CONN_CONNECTED, FR_MACHINE_POST_ENTER, watch_log, false, "post CONNECTED");
204
205 TEST_CASE("INIT -> CONNECTING runs the entry function");
206 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTING) == FR_MACHINE_TRANSITIONED);
207 TEST_CHECK(conn_machine_state(&m) == CONN_CONNECTING);
208 TEST_CHECK(conn_machine_prev(&m) == CONN_INIT);
209
210 TEST_CASE("CONNECTING -> CONNECTED runs exit, pre watchers, enter, post watchers, in that order");
211 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTED) == FR_MACHINE_TRANSITIONED);
212 TEST_CHECK(conn_machine_state(&m) == CONN_CONNECTED);
213 TEST_CHECK(conn_machine_prev(&m) == CONN_CONNECTING);
214 LOG_MATCHES("enter CONNECTING", "exit CONNECTING", "pre CONNECTED", "enter CONNECTED", "post CONNECTED");
215
216 conn_machine_fini(&m);
217 talloc_free(ctx);
218}
219
220static void test_transition_invalid(void)
221{
222 TALLOC_CTX *ctx = talloc_init_const("test");
223 conn_machine_t m;
224
225 log_reset();
226 conn_machine_init(&m, &conn_def, CONN_INIT, NULL);
227 conn_machine_watch_add_any(&m, ctx, CONN_CONNECTED, FR_MACHINE_PRE_ENTER, watch_log, false, "pre CONNECTED");
228
229 TEST_CASE("an unlisted transition is rejected and runs nothing");
230 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTED) == FR_MACHINE_INVALID);
231 TEST_CHECK(conn_machine_state(&m) == CONN_INIT);
232 TEST_CHECK(conn_machine_prev(&m) == CONN_INIT);
233 TEST_CHECK(event_num == 0);
234
235 conn_machine_fini(&m);
236 talloc_free(ctx);
237}
238
239static void test_enter_failed(void)
240{
241 TALLOC_CTX *ctx = talloc_init_const("test");
242 conn_machine_t m;
243
244 log_reset();
245 conn_machine_init(&m, &conn_def, CONN_CONNECTING, NULL);
246 conn_machine_watch_add_any(&m, ctx, CONN_CONNECTED, FR_MACHINE_PRE_ENTER, watch_log, false, "pre CONNECTED");
247 conn_machine_watch_add_any(&m, ctx, CONN_CONNECTED, FR_MACHINE_POST_ENTER, watch_log, false, "post CONNECTED");
248 enter_ret = -1;
249
250 TEST_CASE("a failed entry function reports failure, leaves the machine in the new state, and skips post watchers");
251 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTED) == FR_MACHINE_ENTER_FAILED);
252 TEST_CHECK(conn_machine_state(&m) == CONN_CONNECTED);
253 LOG_MATCHES("exit CONNECTING", "pre CONNECTED", "enter CONNECTED");
254
255 conn_machine_fini(&m);
256 talloc_free(ctx);
257}
258
259static void test_watch_edges(void)
260{
261 TALLOC_CTX *ctx = talloc_init_const("test");
262 conn_machine_t m;
263
264 log_reset();
265 conn_machine_init(&m, &conn_def, CONN_INIT, NULL);
266 conn_machine_watch_add(&m, ctx, CONN_CONNECTING, CONN_FAILED, FR_MACHINE_POST_ENTER, watch_log, false,
267 "edge CONNECTING->FAILED");
268 conn_machine_watch_add(&m, ctx, CONN_CONNECTED, CONN_FAILED, FR_MACHINE_POST_ENTER, watch_log, false,
269 "edge CONNECTED->FAILED");
270 conn_machine_watch_add(&m, ctx, CONN_CONNECTING, FR_MACHINE_STATE_ANY, FR_MACHINE_POST_ENTER, watch_log, false,
271 "exit CONNECTING (watch)");
272 conn_machine_watch_add_any(&m, ctx, CONN_FAILED, FR_MACHINE_POST_ENTER, watch_log, false, "any->FAILED");
273
274 TEST_CASE("INIT -> CONNECTING matches no watcher");
275 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTING) == FR_MACHINE_TRANSITIONED);
276 LOG_MATCHES("enter CONNECTING");
277
278 TEST_CASE("CONNECTING -> FAILED matches the edge, the exit wildcard and the entry wildcard, in registration order");
279 TEST_CHECK(conn_machine_transition(&m, CONN_FAILED) == FR_MACHINE_TRANSITIONED);
280 LOG_MATCHES("enter CONNECTING", "exit CONNECTING", "edge CONNECTING->FAILED", "exit CONNECTING (watch)", "any->FAILED");
281
282 conn_machine_fini(&m);
283 talloc_free(ctx);
284}
285
287{
288 TALLOC_CTX *ctx = talloc_init_const("test");
289 conn_machine_t m;
290 fr_machine_watch_entry_t *persistent;
291
292 log_reset();
293 conn_machine_init(&m, &conn_def, CONN_INIT, NULL);
294 conn_machine_watch_add_any(&m, ctx, CONN_CONNECTING, FR_MACHINE_POST_ENTER, watch_log, true, "oneshot");
295 persistent = conn_machine_watch_add_any(&m, ctx, CONN_CONNECTING, FR_MACHINE_POST_ENTER, watch_log, false,
296 "persistent");
297
298 TEST_CASE("both watchers run on the first entry");
299 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTING) == FR_MACHINE_TRANSITIONED);
300 LOG_MATCHES("enter CONNECTING", "oneshot", "persistent");
301
302 TEST_CASE("only the persistent watcher runs on the second entry");
303 log_reset();
304 TEST_CHECK(conn_machine_transition(&m, CONN_FAILED) == FR_MACHINE_TRANSITIONED);
305 TEST_CHECK(conn_machine_transition(&m, CONN_INIT) == FR_MACHINE_TRANSITIONED);
306 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTING) == FR_MACHINE_TRANSITIONED);
307 LOG_MATCHES("exit CONNECTING", "enter CONNECTING", "persistent");
308
309 TEST_CASE("a disabled watcher is skipped, and runs again once enabled");
310 log_reset();
311 fr_machine_watch_disable(persistent);
312 TEST_CHECK(conn_machine_transition(&m, CONN_FAILED) == FR_MACHINE_TRANSITIONED);
313 TEST_CHECK(conn_machine_transition(&m, CONN_INIT) == FR_MACHINE_TRANSITIONED);
314 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTING) == FR_MACHINE_TRANSITIONED);
315 LOG_MATCHES("exit CONNECTING", "enter CONNECTING");
316
317 log_reset();
318 fr_machine_watch_enable(persistent);
319 TEST_CHECK(conn_machine_transition(&m, CONN_FAILED) == FR_MACHINE_TRANSITIONED);
320 TEST_CHECK(conn_machine_transition(&m, CONN_INIT) == FR_MACHINE_TRANSITIONED);
321 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTING) == FR_MACHINE_TRANSITIONED);
322 LOG_MATCHES("exit CONNECTING", "enter CONNECTING", "persistent");
323
324 TEST_CASE("freeing the handle removes the watcher");
325 log_reset();
326 talloc_free(persistent);
327 TEST_CHECK(conn_machine_transition(&m, CONN_FAILED) == FR_MACHINE_TRANSITIONED);
328 TEST_CHECK(conn_machine_transition(&m, CONN_INIT) == FR_MACHINE_TRANSITIONED);
329 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTING) == FR_MACHINE_TRANSITIONED);
330 LOG_MATCHES("exit CONNECTING", "enter CONNECTING");
331
332 conn_machine_fini(&m);
333 talloc_free(ctx);
334}
335
336/*
337 * A watcher that frees the entry in its uctx, which the test
338 * points at itself or at a sibling.
339 */
340static void watch_free_entry(UNUSED conn_machine_t *m, UNUSED conn_state_t prev, UNUSED conn_state_t state, void *uctx)
341{
342 fr_machine_watch_entry_t **entry_p = uctx;
343
344 log_add("freeing an entry");
345 talloc_free(*entry_p);
346 *entry_p = NULL;
347}
348
350{
351 TALLOC_CTX *ctx = talloc_init_const("test");
352 conn_machine_t m;
353 fr_machine_watch_entry_t *self = NULL, *sibling = NULL;
354
355 log_reset();
356 conn_machine_init(&m, &conn_def, CONN_INIT, NULL);
357
358 TEST_CASE("a watcher that frees itself does not break the walk");
359 self = conn_machine_watch_add_any(&m, ctx, CONN_CONNECTING, FR_MACHINE_POST_ENTER, watch_free_entry, false, &self);
360 conn_machine_watch_add_any(&m, ctx, CONN_CONNECTING, FR_MACHINE_POST_ENTER, watch_log, false, "after self");
361 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTING) == FR_MACHINE_TRANSITIONED);
362 LOG_MATCHES("enter CONNECTING", "freeing an entry", "after self");
363 TEST_CHECK(self == NULL);
364
365 TEST_CASE("a watcher that frees the next sibling skips it and continues");
366 log_reset();
367 TEST_CHECK(conn_machine_transition(&m, CONN_FAILED) == FR_MACHINE_TRANSITIONED);
368 TEST_CHECK(conn_machine_transition(&m, CONN_INIT) == FR_MACHINE_TRANSITIONED);
369 log_reset();
370 conn_machine_watch_add_any(&m, ctx, CONN_CONNECTING, FR_MACHINE_POST_ENTER, watch_free_entry, false, &sibling);
371 sibling = conn_machine_watch_add_any(&m, ctx, CONN_CONNECTING, FR_MACHINE_POST_ENTER, watch_log, false, "sibling");
372 conn_machine_watch_add_any(&m, ctx, CONN_CONNECTING, FR_MACHINE_POST_ENTER, watch_log, false, "after sibling");
373 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTING) == FR_MACHINE_TRANSITIONED);
374 LOG_MATCHES("enter CONNECTING", "after self", "freeing an entry", "after sibling");
375 TEST_CHECK(sibling == NULL);
376
377 conn_machine_fini(&m);
378 talloc_free(ctx);
379}
380
382{
383 TALLOC_CTX *ctx = talloc_init_const("test");
384 conn_machine_t m;
385 conn_state_t to_connected = CONN_CONNECTED;
386 conn_state_t to_closed = CONN_CLOSED;
387
388 log_reset();
389 conn_machine_init(&m, &conn_def, CONN_INIT, NULL);
390 conn_machine_watch_add_any(&m, ctx, CONN_CONNECTING, FR_MACHINE_POST_ENTER, watch_transition, false, &to_connected);
391 conn_machine_watch_add_any(&m, ctx, CONN_CONNECTED, FR_MACHINE_POST_ENTER, watch_log, false, "post CONNECTED");
392
393 TEST_CASE("a transition requested by a watcher runs after the current one completes");
394 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTING) == FR_MACHINE_TRANSITIONED);
395 TEST_CHECK(conn_machine_state(&m) == CONN_CONNECTED);
396 TEST_CHECK(conn_machine_prev(&m) == CONN_CONNECTING);
397 LOG_MATCHES("enter CONNECTING", "watch requests transition", "exit CONNECTING", "enter CONNECTED", "post CONNECTED");
398
399 TEST_CASE("two requests from one callback run in order");
400 log_reset();
401 TEST_CHECK(conn_machine_transition(&m, CONN_FAILED) == FR_MACHINE_TRANSITIONED);
402 TEST_CHECK(conn_machine_transition(&m, CONN_INIT) == FR_MACHINE_TRANSITIONED);
403 log_reset();
404 conn_machine_watch_add_any(&m, ctx, CONN_CONNECTING, FR_MACHINE_POST_ENTER, watch_transition, false, &to_closed);
405 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTING) == FR_MACHINE_TRANSITIONED);
406 TEST_CHECK(conn_machine_state(&m) == CONN_CLOSED);
407 TEST_CHECK(conn_machine_prev(&m) == CONN_CONNECTED);
408 LOG_MATCHES("enter CONNECTING", "watch requests transition", "watch requests transition",
409 "exit CONNECTING", "enter CONNECTED", "post CONNECTED");
410
411 conn_machine_fini(&m);
412 talloc_free(ctx);
413}
414
415static void test_pause_resume(void)
416{
417 TALLOC_CTX *ctx = talloc_init_const("test");
418 conn_machine_t m;
419
420 log_reset();
421 conn_machine_init(&m, &conn_def, CONN_INIT, NULL);
422 conn_machine_watch_add_any(&m, ctx, CONN_CONNECTING, FR_MACHINE_POST_ENTER, watch_log, false, "post CONNECTING");
423
424 TEST_CASE("a transition while paused is queued");
425 conn_machine_pause(&m);
426 conn_machine_pause(&m);
427 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTING) == FR_MACHINE_QUEUED);
428 TEST_CHECK(conn_machine_state(&m) == CONN_INIT);
429 TEST_CHECK(event_num == 0);
430
431 TEST_CASE("the first resume of two does not run the queue");
432 conn_machine_resume(&m);
433 TEST_CHECK(conn_machine_state(&m) == CONN_INIT);
434 TEST_CHECK(event_num == 0);
435
436 TEST_CASE("the last resume runs the queue");
437 conn_machine_resume(&m);
438 TEST_CHECK(conn_machine_state(&m) == CONN_CONNECTING);
439 LOG_MATCHES("enter CONNECTING", "post CONNECTING");
440
441 conn_machine_fini(&m);
442 talloc_free(ctx);
443}
444
445static void test_queue_revalidated(void)
446{
447 TALLOC_CTX *ctx = talloc_init_const("test");
448 conn_machine_t m;
449
450 log_reset();
451 conn_machine_init(&m, &conn_def, CONN_INIT, NULL);
452
453 TEST_CASE("a queued transition the table no longer allows is dropped");
454 conn_machine_pause(&m);
455 TEST_CHECK(conn_machine_transition(&m, CONN_CLOSED) == FR_MACHINE_QUEUED);
456 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTING) == FR_MACHINE_QUEUED); /* Invalid once CLOSED */
457 conn_machine_resume(&m);
458 TEST_CHECK(conn_machine_state(&m) == CONN_CLOSED);
459 TEST_CHECK(event_num == 0);
460
461 conn_machine_fini(&m);
462 talloc_free(ctx);
463}
464
465static void test_watch_ctx_free(void)
466{
467 TALLOC_CTX *ctx = talloc_init_const("test");
468 TALLOC_CTX *watch_ctx = talloc_init_const("watcher");
469 conn_machine_t m;
470
471 log_reset();
472 conn_machine_init(&m, &conn_def, CONN_INIT, NULL);
473 conn_machine_watch_add_any(&m, watch_ctx, CONN_CONNECTING, FR_MACHINE_POST_ENTER, watch_log, false, "from freed ctx");
474 conn_machine_watch_add_any(&m, ctx, CONN_CONNECTING, FR_MACHINE_POST_ENTER, watch_log, false, "from live ctx");
475
476 TEST_CASE("freeing the talloc context of a watcher removes it");
477 talloc_free(watch_ctx);
478 TEST_CHECK(conn_machine_transition(&m, CONN_CONNECTING) == FR_MACHINE_TRANSITIONED);
479 LOG_MATCHES("enter CONNECTING", "from live ctx");
480
481 TEST_CASE("fini frees the remaining watchers, and the context they were parented to is then empty");
482 conn_machine_fini(&m);
483 TEST_CHECK(talloc_total_blocks(ctx) == 1);
484
485 talloc_free(ctx);
486}
487
489 { "init", test_init },
490 { "table", test_table },
491 { "transition_order", test_transition_order },
492 { "transition_invalid", test_transition_invalid },
493 { "enter_failed", test_enter_failed },
494 { "watch_edges", test_watch_edges },
495 { "watch_oneshot_and_disable", test_watch_oneshot_and_disable },
496 { "watch_free_during_walk", test_watch_free_during_walk },
497 { "transition_from_watcher", test_transition_from_watcher },
498 { "pause_resume", test_pause_resume },
499 { "queue_revalidated", test_queue_revalidated },
500 { "watch_ctx_free", test_watch_ctx_free },
502};
#define TEST_CHECK(cond)
Definition acutest.h:101
#define TEST_CASE(name)
Definition acutest.h:203
#define TEST_ASSERT(cond)
Definition acutest.h:125
#define TEST_TERMINATOR
Definition acutest.h:77
#define TEST_MSG(...)
Definition acutest.h:234
Common initialisation for acutest binaries.
#define UNUSED
Definition build.h:415
#define NUM_ELEMENTS(_t)
Definition build.h:437
talloc_free(hp)
char const * fr_machine_state_name(fr_machine_t *m, int state)
Get the name of a particular state.
Definition machine.c:483
Hooks.
Definition machine.c:43
fr_machine_func_t enter
run this when entering the state
Definition machine.h:43
static bool log_matches(char const *const expected[], size_t expected_num)
TEST_LIST
#define CONN_ROW(_from,...)
static fr_machine_def_t const conn_def
static int conn_enter_connected(UNUSED fr_machine_t *m, UNUSED void *uctx)
static void log_reset(void)
FR_MACHINE_VALID(conn, CONN_MAX, CONN_ROW(CONN_INIT, CONN_CONNECTING, CONN_CLOSED), CONN_ROW(CONN_CONNECTING, CONN_CONNECTED, CONN_FAILED, CONN_CLOSED), CONN_ROW(CONN_CONNECTED, CONN_FAILED, CONN_CLOSED),)
#define LOG_MATCHES(...)
static size_t event_num
static void test_table(void)
static int enter_ret
static void test_enter_failed(void)
static void conn_exit_connecting(UNUSED fr_machine_t *m, UNUSED void *uctx)
static int conn_enter_connecting(UNUSED fr_machine_t *m, UNUSED void *uctx)
static void test_transition_from_watcher(void)
static void test_pause_resume(void)
conn_state_t
@ CONN_MAX
@ CONN_INIT
@ CONN_CONNECTING
@ CONN_CLOSED
@ CONN_FAILED
@ CONN_CONNECTED
static void watch_transition(conn_machine_t *m, UNUSED conn_state_t prev, UNUSED conn_state_t state, void *uctx)
static void test_watch_oneshot_and_disable(void)
static char const * event_log[LOG_MAX]
static void test_watch_free_during_walk(void)
static fr_machine_state_t const conn_states[CONN_MAX]
static void test_transition_invalid(void)
static void log_add(char const *event)
#define LOG_MAX
static void test_init(void)
static fr_table_num_indexed_t const conn_state_names[]
static void test_watch_ctx_free(void)
static void watch_free_entry(UNUSED conn_machine_t *m, UNUSED conn_state_t prev, UNUSED conn_state_t state, void *uctx)
static void test_queue_revalidated(void)
static void test_watch_edges(void)
static void test_transition_order(void)
static void watch_log(UNUSED conn_machine_t *m, UNUSED conn_state_t prev, UNUSED conn_state_t state, void *uctx)
#define FR_TABLE_INDEXED_ENTRY(_v)
Build a single fr_table_num_indexed_t entry from an enum identifier.
Definition table.h:110
An element in a table indexed by numeric value.
Definition table.h:92
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
Definition talloc.h:127