blob: 710a4aa004713909e21fd5c66c97f90fec1fe52a [file] [log] [blame]
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +01001/* Test implementation for osmo_tdef API. */
2/*
3 * (C) 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
4 *
5 * All Rights Reserved
6 *
7 * SPDX-License-Identifier: GPL-2.0+
8 *
9 * Author: Neels Hofmeyr <neels@hofmeyr.de>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +010020 */
21
22#include <stdio.h>
23#include <errno.h>
24#include <limits.h>
25
26#include <osmocom/core/logging.h>
27#include <osmocom/core/application.h>
28#include <osmocom/core/fsm.h>
29
30#include <osmocom/core/tdef.h>
31
32static void *ctx = NULL;
33
34static struct osmo_tdef tdefs[] = {
35 { .T=1, .default_val=100, .desc="100s" },
36 { .T=2, .default_val=100, .unit=OSMO_TDEF_MS, .desc="100ms" },
Pau Espin Pedrole81c2f42020-11-15 17:52:09 +010037 { .T=3, .default_val=50, .unit=OSMO_TDEF_M, .desc="50m" },
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +010038 { .T=4, .default_val=100, .unit=OSMO_TDEF_CUSTOM, .desc="100 potatoes" },
39
Vadim Yanitskiye30d22a2023-12-30 04:22:26 +070040 { .T=-5, .default_val=100, .unit=OSMO_TDEF_MS, .desc="X-100ms" },
41 { .T=-6, .default_val=100, .unit=OSMO_TDEF_US, .desc="X-100us" },
42
Pau Espin Pedrol0cbe8f02019-09-17 13:13:52 +020043 { .T=7, .default_val=50, .desc="Water Boiling Timeout", .min_val=20, .max_val=800 }, // default is .unit=OSMO_TDEF_S == 0
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +010044 { .T=8, .default_val=300, .desc="Tea brewing" },
45 { .T=9, .default_val=5, .unit=OSMO_TDEF_M, .desc="Let tea cool down before drinking" },
46 { .T=10, .default_val=20, .unit=OSMO_TDEF_M, .desc="Forgot to drink tea while it's warm" },
47
48 /* test conversions */
49 { .T=1000, .default_val=2*1000, .unit=OSMO_TDEF_MS, .desc="two seconds from ms" },
Pau Espin Pedrol2299cb52020-11-15 17:58:10 +010050 { .T=1001, .default_val=60*1000, .unit=OSMO_TDEF_MS, .desc="one minute from ms" },
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +010051 { .T=1004, .default_val=1, .unit=OSMO_TDEF_MS, .desc="one ms" },
52 { .T=1005, .default_val=0, .unit=OSMO_TDEF_MS, .desc="zero ms" },
53 { .T=1006, .default_val=0, .unit=OSMO_TDEF_S, .desc="zero s" },
54 { .T=1007, .default_val=0, .unit=OSMO_TDEF_M, .desc="zero m" },
55 { .T=1008, .default_val=0, .unit=OSMO_TDEF_CUSTOM, .desc="zero" },
Pau Espin Pedrol1b75e4b2020-11-04 20:00:38 +010056 { .T=1009, .default_val=0, .unit=OSMO_TDEF_US, .desc="zero us" },
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +010057
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +010058 { .T=0, .default_val=1, .unit=OSMO_TDEF_CUSTOM, .desc="zero" },
59
60 /* no desc */
61 { .T=123, .default_val=1 },
62
63 {} // <-- important! last entry shall be zero
64};
65
Neels Hofmeyr7b740f72019-02-06 01:08:43 +010066static struct osmo_tdef tdefs_range[] = {
67 { .T=1002, .default_val=(ULONG_MAX/60), .unit=OSMO_TDEF_M, .desc="almost too many seconds" },
68 { .T=1003, .default_val=ULONG_MAX, .unit=OSMO_TDEF_M, .desc="too many seconds" },
69
70 { .T=INT_MAX, .default_val=ULONG_MAX, .unit=OSMO_TDEF_S, .desc="very large" },
71 { .T=INT_MAX-1, .default_val=ULONG_MAX-1, .unit=OSMO_TDEF_S, .desc="very large" },
72 { .T=INT_MAX-2, .default_val=LONG_MAX, .unit=OSMO_TDEF_S, .desc="very large" },
73 { .T=INT_MAX-3, .default_val=ULONG_MAX, .unit=OSMO_TDEF_M, .desc="very large in minutes" },
74 { .T=INT_MIN, .default_val=ULONG_MAX, .unit=OSMO_TDEF_S, .desc="negative" },
75
76 {}
77};
78
79#define print_tdef_get(TDEFS, T, AS_UNIT) do { \
80 unsigned long val = osmo_tdef_get(TDEFS, T, AS_UNIT, 999); \
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +010081 printf("osmo_tdef_get(tdefs, %d, %s, 999)\t= %lu\n", T, osmo_tdef_unit_name(AS_UNIT), val); \
82 } while (0)
83
Neels Hofmeyr7b740f72019-02-06 01:08:43 +010084#define print_tdef_get_short(TDEFS, T, AS_UNIT) do { \
85 unsigned long val = osmo_tdef_get(TDEFS, T, AS_UNIT, 999); \
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +010086 printf("osmo_tdef_get(%d, %s)\t= %lu\n", T, osmo_tdef_unit_name(AS_UNIT), val); \
87 } while (0)
88
Vadim Yanitskiy19b07c32024-01-04 06:36:09 +070089void print_tdef_info(int T)
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +010090{
91 const struct osmo_tdef *t = osmo_tdef_get_entry(tdefs, T);
92 if (!t) {
Vadim Yanitskiy19b07c32024-01-04 06:36:09 +070093 printf(OSMO_T_FMT "=NULL", OSMO_T_FMT_ARGS(T));
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +010094 return;
95 }
Vadim Yanitskiy19b07c32024-01-04 06:36:09 +070096 printf(OSMO_T_FMT "=%lu%s",
97 OSMO_T_FMT_ARGS(T), t->val, osmo_tdef_unit_name(t->unit));
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +010098 if (t->val != t->default_val)
99 printf("(def=%lu)", t->default_val);
100 printf("\n");
101}
102
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100103static void test_tdef_get(bool test_range)
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100104{
105 int i;
106 enum osmo_tdef_unit as_unit;
107
108 printf("\n%s()\n", __func__);
109
110 osmo_tdefs_reset(tdefs); // make all values the default
111
112 for (i = 0; i < ARRAY_SIZE(tdefs)-1; i++) {
Vadim Yanitskiy19b07c32024-01-04 06:36:09 +0700113 int T = tdefs[i].T;
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100114 print_tdef_info(T);
Pau Espin Pedrol1b75e4b2020-11-04 20:00:38 +0100115 for (as_unit = OSMO_TDEF_S; as_unit <= OSMO_TDEF_US; as_unit++) {
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100116 print_tdef_get_short(tdefs, T, as_unit);
117 }
118 }
119
120 if (!test_range)
121 return;
122
123 for (i = 0; i < ARRAY_SIZE(tdefs_range)-1; i++) {
Vadim Yanitskiy19b07c32024-01-04 06:36:09 +0700124 int T = tdefs_range[i].T;
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100125 print_tdef_info(T);
Pau Espin Pedrol1b75e4b2020-11-04 20:00:38 +0100126 for (as_unit = OSMO_TDEF_S; as_unit <= OSMO_TDEF_US; as_unit++) {
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100127 print_tdef_get_short(tdefs_range, T, as_unit);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100128 }
129 }
130}
131
Harald Weltee61d4592022-11-03 11:05:58 +0100132static void test_tdef_get_nonexisting(void)
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100133{
134 printf("\n%s()\n", __func__);
135
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100136 print_tdef_get(tdefs, 5, OSMO_TDEF_S);
137 print_tdef_get(tdefs, 5, OSMO_TDEF_MS);
138 print_tdef_get(tdefs, 5, OSMO_TDEF_M);
139 print_tdef_get(tdefs, 5, OSMO_TDEF_CUSTOM);
Pau Espin Pedrol1b75e4b2020-11-04 20:00:38 +0100140 print_tdef_get(tdefs, 5, OSMO_TDEF_US);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100141}
142
Harald Weltee61d4592022-11-03 11:05:58 +0100143static void test_tdef_set_and_get(void)
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100144{
145 struct osmo_tdef *t;
146 printf("\n%s()\n", __func__);
147
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100148 printf("setting 7 = 42\n");
Pau Espin Pedrol0cbe8f02019-09-17 13:13:52 +0200149 t = osmo_tdef_get_entry(tdefs, 7);
Vadim Yanitskiy342a5222022-07-20 05:10:04 +0700150 OSMO_ASSERT(t != NULL);
Pau Espin Pedrol0cbe8f02019-09-17 13:13:52 +0200151 OSMO_ASSERT(osmo_tdef_val_in_range(t, 42));
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100152 t->val = 42;
153 print_tdef_info(7);
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100154 print_tdef_get_short(tdefs, 7, OSMO_TDEF_MS);
155 print_tdef_get_short(tdefs, 7, OSMO_TDEF_S);
156 print_tdef_get_short(tdefs, 7, OSMO_TDEF_M);
157 print_tdef_get_short(tdefs, 7, OSMO_TDEF_CUSTOM);
Pau Espin Pedrol1b75e4b2020-11-04 20:00:38 +0100158 print_tdef_get_short(tdefs, 7, OSMO_TDEF_US);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100159
160 printf("setting 7 = 420\n");
Pau Espin Pedrol0cbe8f02019-09-17 13:13:52 +0200161 OSMO_ASSERT(osmo_tdef_set(tdefs, 7, 420, OSMO_TDEF_S) == 0);
162 print_tdef_info(7);
163 print_tdef_get_short(tdefs, 7, OSMO_TDEF_MS);
164 print_tdef_get_short(tdefs, 7, OSMO_TDEF_S);
165 print_tdef_get_short(tdefs, 7, OSMO_TDEF_M);
166 print_tdef_get_short(tdefs, 7, OSMO_TDEF_CUSTOM);
Pau Espin Pedrol1b75e4b2020-11-04 20:00:38 +0100167 print_tdef_get_short(tdefs, 7, OSMO_TDEF_US);
Pau Espin Pedrol0cbe8f02019-09-17 13:13:52 +0200168
169 printf("setting 7 = 10 (ERANGE)\n");
170 OSMO_ASSERT(!osmo_tdef_val_in_range(t, 10));
171 OSMO_ASSERT(osmo_tdef_set(tdefs, 7, 10, OSMO_TDEF_S) == -ERANGE);
172 print_tdef_info(7);
173 print_tdef_get_short(tdefs, 7, OSMO_TDEF_MS);
174 print_tdef_get_short(tdefs, 7, OSMO_TDEF_S);
175 print_tdef_get_short(tdefs, 7, OSMO_TDEF_M);
176 print_tdef_get_short(tdefs, 7, OSMO_TDEF_CUSTOM);
Pau Espin Pedrol1b75e4b2020-11-04 20:00:38 +0100177 print_tdef_get_short(tdefs, 7, OSMO_TDEF_US);
Pau Espin Pedrol0cbe8f02019-09-17 13:13:52 +0200178
179 printf("setting 7 = 900 (ERANGE)\n");
180 OSMO_ASSERT(!osmo_tdef_val_in_range(t, 900));
181 OSMO_ASSERT(osmo_tdef_set(tdefs, 7, 900, OSMO_TDEF_S) == -ERANGE);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100182 print_tdef_info(7);
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100183 print_tdef_get_short(tdefs, 7, OSMO_TDEF_MS);
184 print_tdef_get_short(tdefs, 7, OSMO_TDEF_S);
185 print_tdef_get_short(tdefs, 7, OSMO_TDEF_M);
186 print_tdef_get_short(tdefs, 7, OSMO_TDEF_CUSTOM);
Pau Espin Pedrol1b75e4b2020-11-04 20:00:38 +0100187 print_tdef_get_short(tdefs, 7, OSMO_TDEF_US);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100188
Pau Espin Pedrol9168cc92019-09-18 13:18:18 +0200189 printf("setting 23 = 50 (EEXIST)\n");
190 OSMO_ASSERT(osmo_tdef_set(tdefs, 23, 50, OSMO_TDEF_S) == -EEXIST);
191
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100192 printf("resetting\n");
193 osmo_tdefs_reset(tdefs);
194 print_tdef_info(7);
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100195 print_tdef_get_short(tdefs, 7, OSMO_TDEF_S);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100196}
197
198enum test_tdef_fsm_states {
199 S_A = 0,
200 S_B,
201 S_C,
202 S_D,
Vadim Yanitskiye30d22a2023-12-30 04:22:26 +0700203 S_E,
204 S_F,
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100205 S_G,
206 S_H,
207 S_I,
208 S_J,
209 S_K,
210 S_L,
211 S_M,
212 S_N,
213 S_O,
Vadim Yanitskiye30d22a2023-12-30 04:22:26 +0700214 /* ... gap ... */
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100215 S_X,
216 S_Y,
217 S_Z,
218};
219
220static const struct osmo_tdef_state_timeout test_tdef_state_timeouts[32] = {
221 [S_A] = { .T = 1 },
222 [S_B] = { .T = 2 },
223 [S_C] = { .T = 3 },
224 [S_D] = { .T = 4 },
225
Vadim Yanitskiye30d22a2023-12-30 04:22:26 +0700226 [S_E] = { .T = -5 },
227 [S_F] = { .T = -6 },
228
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100229 [S_G] = { .T = 7 },
230 [S_H] = { .T = 8 },
231 [S_I] = { .T = 9 },
232 [S_J] = { .T = 10 },
233
234 /* keep_timer: adopt whichever T was running before and continue the timeout. */
235 [S_K] = { .keep_timer = true },
236 /* S_F defines an undefined T, but should continue previous state's timeout. */
237 [S_L] = { .T = 123, .keep_timer = true },
238
239 /* range */
240 [S_M] = { .T = INT_MAX },
241 [S_N] = { .T = INT_MIN },
242
243 /* T0 is not addressable from osmo_tdef_state_timeout, since it is indistinguishable from an unset entry. Even
244 * though a timeout value is set for T=0, the transition to state S_O will show "no timer configured". */
245 [S_O] = { .T = 0 },
246
247 /* S_X undefined on purpose */
248 /* S_Y defines a T that does not exist */
249 [S_Y] = { .T = 666 },
250 /* S_Z undefined on purpose */
251};
252
253#define S(x) (1 << (x))
254
255static const struct osmo_fsm_state test_tdef_fsm_states[] = {
256#define DEF_STATE(NAME) \
257 [S_##NAME] = { \
258 .name = #NAME, \
Vadim Yanitskiye30d22a2023-12-30 04:22:26 +0700259 .out_state_mask = 0xffffffff, \
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100260 }
261
262 DEF_STATE(A),
263 DEF_STATE(B),
264 DEF_STATE(C),
265 DEF_STATE(D),
Vadim Yanitskiye30d22a2023-12-30 04:22:26 +0700266 DEF_STATE(E),
267 DEF_STATE(F),
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100268 DEF_STATE(G),
269 DEF_STATE(H),
270 DEF_STATE(I),
271 DEF_STATE(J),
272
273 DEF_STATE(K),
274 DEF_STATE(L),
275
276 DEF_STATE(M),
277 DEF_STATE(N),
278 DEF_STATE(O),
279
280 DEF_STATE(X),
281 DEF_STATE(Y),
282 /* Z: test not being allowed to transition to other states. */
283 [S_Z] = {
284 .name = "Z",
285 .out_state_mask = 0
286 | S(S_A)
287 ,
288 },
289};
290
291static const struct value_string test_tdef_fsm_event_names[] = { {} };
292
293static struct osmo_fsm test_tdef_fsm = {
294 .name = "tdef_test",
295 .states = test_tdef_fsm_states,
296 .event_names = test_tdef_fsm_event_names,
297 .num_states = ARRAY_SIZE(test_tdef_fsm_states),
298 .log_subsys = DLGLOBAL,
299};
300
301const struct timeval fake_time_start_time = { 123, 456 };
302
303#define fake_time_passes(secs, usecs) do \
304{ \
305 struct timeval diff; \
306 osmo_gettimeofday_override_add(secs, usecs); \
307 osmo_clock_override_add(CLOCK_MONOTONIC, secs, usecs * 1000); \
308 timersub(&osmo_gettimeofday_override_time, &fake_time_start_time, &diff); \
Neels Hofmeyr4f54c6c2019-03-06 06:03:24 +0100309 printf("Time passes: %ld.%06ld s\n", (long)secs, (long)usecs); \
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100310 osmo_timers_prepare(); \
311 osmo_timers_update(); \
312} while (0)
313
Harald Weltee61d4592022-11-03 11:05:58 +0100314void fake_time_start(void)
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100315{
316 struct timespec *clock_override;
317
318 osmo_gettimeofday_override_time = fake_time_start_time;
319 osmo_gettimeofday_override = true;
320 clock_override = osmo_clock_override_gettimespec(CLOCK_MONOTONIC);
321 OSMO_ASSERT(clock_override);
322 clock_override->tv_sec = fake_time_start_time.tv_sec;
323 clock_override->tv_nsec = fake_time_start_time.tv_usec * 1000;
324 osmo_clock_override_enable(CLOCK_MONOTONIC, true);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100325}
326
327static void print_fsm_state(struct osmo_fsm_inst *fi)
328{
329 struct timeval remaining;
330 printf("state=%s T=%d", osmo_fsm_inst_state_name(fi), fi->T);
331
332 if (!osmo_timer_pending(&fi->timer)) {
333 printf(", no timeout\n");
334 return;
335 }
336
337 osmo_timer_remaining(&fi->timer, &osmo_gettimeofday_override_time, &remaining);
338 printf(", %lu.%06lu s remaining\n", remaining.tv_sec, remaining.tv_usec);
339}
340
341
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100342#define test_tdef_fsm_state_chg(tdefs, NEXT_STATE) do { \
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100343 const struct osmo_tdef_state_timeout *st = osmo_tdef_get_state_timeout(NEXT_STATE, \
344 test_tdef_state_timeouts); \
Neels Hofmeyr4ea69822019-03-06 06:14:01 +0100345 int rc = osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, test_tdef_state_timeouts, tdefs, 999); \
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100346 if (!st) { \
Neels Hofmeyr4ea69822019-03-06 06:14:01 +0100347 printf(" --> %s (no timer configured for this state) rc=%d;\t", \
348 osmo_fsm_state_name(&test_tdef_fsm, NEXT_STATE), rc); \
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100349 } else { \
350 struct osmo_tdef *t = osmo_tdef_get_entry(tdefs, st->T); \
Vadim Yanitskiy19b07c32024-01-04 06:36:09 +0700351 printf(" --> %s (configured as " OSMO_T_FMT "%s %lu %s) rc=%d;\t", \
Neels Hofmeyr4f54c6c2019-03-06 06:03:24 +0100352 osmo_fsm_state_name(&test_tdef_fsm, NEXT_STATE), \
Vadim Yanitskiy19b07c32024-01-04 06:36:09 +0700353 OSMO_T_FMT_ARGS(st->T), st->keep_timer ? " (keep_timer)" : "", \
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100354 t? t->val : 0, t? osmo_tdef_unit_name(t->unit) : "-", \
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100355 rc); \
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100356 } \
Neels Hofmeyr4f54c6c2019-03-06 06:03:24 +0100357 print_fsm_state(fi); \
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100358 } while(0)
359
360
361
362static void test_tdef_state_timeout(bool test_range)
363{
364 struct osmo_fsm_inst *fi;
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100365 unsigned long m_secs;
366 printf("\n%s()\n", __func__);
367
368 osmo_tdefs_reset(tdefs);
369
370 fake_time_start();
371
372 fi = osmo_fsm_inst_alloc(&test_tdef_fsm, ctx, NULL, LOGL_DEBUG, __func__);
373 OSMO_ASSERT(fi);
374 print_fsm_state(fi);
375
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100376 test_tdef_fsm_state_chg(tdefs, S_A);
377 test_tdef_fsm_state_chg(tdefs, S_B);
378 test_tdef_fsm_state_chg(tdefs, S_C);
379 test_tdef_fsm_state_chg(tdefs, S_D);
Vadim Yanitskiye30d22a2023-12-30 04:22:26 +0700380 test_tdef_fsm_state_chg(tdefs, S_E);
381 test_tdef_fsm_state_chg(tdefs, S_F);
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100382 test_tdef_fsm_state_chg(tdefs, S_G);
383 test_tdef_fsm_state_chg(tdefs, S_H);
384 test_tdef_fsm_state_chg(tdefs, S_I);
385 test_tdef_fsm_state_chg(tdefs, S_J);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100386
387 printf("- test keep_timer:\n");
388 fake_time_passes(123, 45678);
389 print_fsm_state(fi);
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100390 test_tdef_fsm_state_chg(tdefs, S_K);
391 test_tdef_fsm_state_chg(tdefs, S_A);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100392 fake_time_passes(23, 45678);
393 print_fsm_state(fi);
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100394 test_tdef_fsm_state_chg(tdefs, S_K);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100395
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100396 test_tdef_fsm_state_chg(tdefs, S_A);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100397 fake_time_passes(23, 45678);
398 print_fsm_state(fi);
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100399 test_tdef_fsm_state_chg(tdefs, S_L);
Neels Hofmeyr4f54c6c2019-03-06 06:03:24 +0100400 test_tdef_fsm_state_chg(tdefs, S_O);
401 test_tdef_fsm_state_chg(tdefs, S_L);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100402
403 printf("- test T=0:\n");
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100404 test_tdef_fsm_state_chg(tdefs, S_O);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100405
406 printf("- test no timer:\n");
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100407 test_tdef_fsm_state_chg(tdefs, S_X);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100408
409 printf("- test undefined timer, using default_val arg of osmo_tdef_fsm_inst_state_chg(), here passed as 999:\n");
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100410 test_tdef_fsm_state_chg(tdefs, S_Y);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100411
412 /* the range of unsigned long is architecture dependent. This test can be invoked manually to see whether
413 * clamping the timeout values works, but the output will be of varying lengths depending on the system's
414 * unsigned long range, and would cause differences in expected output. */
415 if (test_range) {
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100416 struct osmo_tdef *m;
417
418 printf("- test large T:\n");
419 test_tdef_fsm_state_chg(tdefs_range, S_M);
420
421 printf("- test T<0:\n");
422 test_tdef_fsm_state_chg(tdefs_range, S_N);
423
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100424 printf("- test range:\n");
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100425 test_tdef_fsm_state_chg(tdefs_range, S_M);
426
427 m = osmo_tdef_get_entry(tdefs_range, INT_MAX);
428 OSMO_ASSERT(m);
429
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100430 /* sweep through all the bits, shifting in 0xfffff.. from the right. */
431 m_secs = 0;
432 do {
433 m_secs = (m_secs << 1) + 1;
434 switch (m_secs) {
435 case 0x7fff:
436 printf("--- int32_t max ---\n");
437 break;
438 case 0xffff:
439 printf("--- uint32_t max ---\n");
440 break;
441 case 0x7fffffff:
442 printf("--- int64_t max ---\n");
443 break;
444 case 0xffffffff:
445 printf("--- uint64_t max ---\n");
446 break;
447 default:
448 break;
449 }
450
451 m->val = m_secs - 1;
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100452 test_tdef_fsm_state_chg(tdefs_range, S_M);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100453 m->val = m_secs;
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100454 test_tdef_fsm_state_chg(tdefs_range, S_M);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100455 m->val = m_secs + 1;
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100456 test_tdef_fsm_state_chg(tdefs_range, S_M);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100457 } while (m_secs < ULONG_MAX);
458 }
459
460 printf("- test disallowed transition:\n");
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100461 test_tdef_fsm_state_chg(tdefs, S_Z);
462 test_tdef_fsm_state_chg(tdefs, S_B);
463 test_tdef_fsm_state_chg(tdefs, S_C);
464 test_tdef_fsm_state_chg(tdefs, S_D);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100465}
466
467int main(int argc, char **argv)
468{
469 ctx = talloc_named_const(NULL, 0, "tdef_test.c");
470 osmo_init_logging2(ctx, NULL);
471
Pau Espin Pedrol01e0d3e2021-02-18 19:25:44 +0100472 log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
Vadim Yanitskiy3c5518c2023-12-30 23:39:09 +0700473 log_set_print_level(osmo_stderr_target, 1);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100474 log_set_print_category(osmo_stderr_target, 1);
Vadim Yanitskiy3c5518c2023-12-30 23:39:09 +0700475 log_set_print_category_hex(osmo_stderr_target, 0);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100476 log_set_use_color(osmo_stderr_target, 0);
477
Vadim Yanitskiy3c5518c2023-12-30 23:39:09 +0700478 osmo_fsm_log_addr(false);
479 osmo_fsm_log_timeouts(true);
480
481 log_set_category_filter(osmo_stderr_target, DLGLOBAL, 1, LOGL_DEBUG);
482
Harald Welteae5016f2019-12-01 13:38:20 +0100483 OSMO_ASSERT(osmo_fsm_register(&test_tdef_fsm) == 0);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100484
Neels Hofmeyr7b740f72019-02-06 01:08:43 +0100485 test_tdef_get(argc > 1);
Neels Hofmeyr0fd615f2019-01-26 20:36:12 +0100486 test_tdef_get_nonexisting();
487 test_tdef_set_and_get();
488 /* Run range test iff any argument is passed on the cmdline. For the rationale, see the comment in
489 * test_tdef_state_timeout(). */
490 test_tdef_state_timeout(argc > 1);
491
492 return EXIT_SUCCESS;
493}