]> git.ipfire.org Git - thirdparty/bird.git/blame - test/birdtest.c
BFD: Fix reconfiguration of neighbors
[thirdparty/bird.git] / test / birdtest.c
CommitLineData
9b0a0ba9
OZ
1/*
2 * BIRD -- Unit Test Framework (BIRD Test)
3 *
4 * Can be freely distributed and used under the terms of the GNU GPL.
5 */
6
7#include <stdarg.h>
8#include <stdint.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <signal.h>
13#include <unistd.h>
14
15#include <sys/ioctl.h>
16#include <sys/resource.h>
17#include <sys/wait.h>
18
19#include "test/birdtest.h"
20#include "lib/string.h"
21
22#ifdef HAVE_EXECINFO_H
23#include <execinfo.h>
24#endif
25
26#define BACKTRACE_MAX_LINES 100
27
28#define sprintf_concat(s, format, ...) \
29 snprintf(s + strlen(s), sizeof(s) - strlen(s), format, ##__VA_ARGS__)
30
31static const char *request;
32static int list_tests;
33static int do_core;
d348a916 34static int do_die;
9b0a0ba9
OZ
35static int no_fork;
36static int no_timeout;
37static int is_terminal; /* Whether stdout is a live terminal or pipe redirect */
38
39uint bt_verbose;
40const char *bt_filename;
41const char *bt_test_id;
42
43int bt_result; /* Overall program run result */
44int bt_suite_result; /* One suit result */
45char bt_out_fmt_buf[1024]; /* Temporary memory buffer for output of testing function */
46
bb001af0
MM
47u64 bt_random_state[] = {
48 0x80241f302bd4d95d, 0xd10ba2e910f772b, 0xea188c9046f507c5, 0x4c4c581f04e6da05,
49 0x53d9772877c1b647, 0xab8ce3eb466de6c5, 0xad02844c8a8e865f, 0xe8cc78080295065d
50};
9b0a0ba9
OZ
51
52void
53bt_init(int argc, char *argv[])
54{
55 int c;
56
bb001af0 57 initstate(BT_RANDOM_SEED, (char *) bt_random_state, sizeof(bt_random_state));
9b0a0ba9
OZ
58
59 bt_verbose = 0;
60 bt_filename = argv[0];
5e3cd0e5 61 bt_result = 1;
9b0a0ba9
OZ
62 bt_test_id = NULL;
63 is_terminal = isatty(fileno(stdout));
64
d348a916 65 while ((c = getopt(argc, argv, "lcdftv")) >= 0)
9b0a0ba9
OZ
66 switch (c)
67 {
68 case 'l':
69 list_tests = 1;
70 break;
71
72 case 'c':
73 do_core = 1;
74 break;
75
d348a916
MM
76 case 'd':
77 do_die = 1;
78 break;
79
9b0a0ba9
OZ
80 case 'f':
81 no_fork = 1;
82 break;
83
84 case 't':
85 no_timeout = 1;
86 break;
87
88 case 'v':
89 bt_verbose++;
90 break;
91
92 default:
93 goto usage;
94 }
95
96 /* Optional requested test_id */
97 if ((optind + 1) == argc)
98 request = argv[optind++];
99
100 if (optind != argc)
101 goto usage;
102
103 if (do_core)
104 {
105 struct rlimit rl = {RLIM_INFINITY, RLIM_INFINITY};
106 int rv = setrlimit(RLIMIT_CORE, &rl);
107 bt_syscall(rv < 0, "setrlimit RLIMIT_CORE");
108 }
109
110 return;
111
112 usage:
d348a916 113 printf("Usage: %s [-l] [-c] [-d] [-f] [-t] [-vvv] [<test_suit_name>]\n", argv[0]);
9b0a0ba9
OZ
114 printf("Options: \n");
115 printf(" -l List all test suite names and descriptions \n");
116 printf(" -c Force unlimit core dumps (needs root privileges) \n");
d348a916 117 printf(" -d Die on first failed test case \n");
9b0a0ba9
OZ
118 printf(" -f No forking \n");
119 printf(" -t No timeout limit \n");
120 printf(" -v More verbosity, maximum is 3 -vvv \n");
121 exit(3);
122}
123
124static void
125bt_dump_backtrace(void)
126{
127#ifdef HAVE_EXECINFO_H
128 void *buf[BACKTRACE_MAX_LINES];
129 char **pp_backtrace;
130 int lines, j;
131
132 if (!bt_verbose)
133 return;
134
135 lines = backtrace(buf, BACKTRACE_MAX_LINES);
136 bt_log("backtrace() returned %d addresses", lines);
137
138 pp_backtrace = backtrace_symbols(buf, lines);
139 if (pp_backtrace == NULL)
140 {
141 perror("backtrace_symbols");
142 exit(EXIT_FAILURE);
143 }
144
145 for (j = 0; j < lines; j++)
146 bt_log("%s", pp_backtrace[j]);
147
148 free(pp_backtrace);
149#endif /* HAVE_EXECINFO_H */
150}
151
152static
153int bt_run_test_fn(int (*fn)(const void *), const void *fn_arg, int timeout)
154{
155 int result;
156 alarm(timeout);
157
0a793ebc 158 result = fn(fn_arg);
9b0a0ba9 159
5e3cd0e5
PT
160 if (!bt_suite_result)
161 result = 0;
9b0a0ba9
OZ
162
163 return result;
164}
165
166static uint
167get_num_terminal_cols(void)
168{
169 struct winsize w = {};
170 ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
171 uint cols = w.ws_col;
172 return (cols > 0 ? cols : 80);
173}
174
175/**
176 * bt_log_result - pretty print of test result
5e3cd0e5 177 * @result: 1 or 0
9b0a0ba9
OZ
178 * @fmt: a description message (could be long, over more lines)
179 * @argptr: variable argument list
180 *
181 * This function is used for pretty printing of test results on all verbose
182 * levels.
183 */
184static void
185bt_log_result(int result, const char *fmt, va_list argptr)
186{
fa71b268 187 static char msg_buf[BT_BUFFER_SIZE];
9b0a0ba9
OZ
188 char *pos;
189
190 snprintf(msg_buf, sizeof(msg_buf), "%s%s%s%s",
191 bt_filename,
192 bt_test_id ? ": " : "",
193 bt_test_id ? bt_test_id : "",
194 (fmt && strlen(fmt) > 0) ? ": " : "");
195 pos = msg_buf + strlen(msg_buf);
196
197 vsnprintf(pos, sizeof(msg_buf) - (pos - msg_buf), fmt, argptr);
198
fa71b268 199 int chrs = 0;
eeba61cc 200 for (uint i = 0; i < strlen(msg_buf); i += get_num_terminal_cols())
fa71b268
PT
201 {
202 if (i)
203 printf("\n");
204 char *stop = msg_buf + i + get_num_terminal_cols();
205 char backup = *stop;
206 *stop = 0;
207 chrs = printf("%s", msg_buf + i);
208 *stop = backup;
209 }
210
211 int offset = get_num_terminal_cols() - chrs - BT_PROMPT_OK_FAIL_STRLEN;
212 if (offset < 0)
213 {
214 printf("\n");
215 offset = get_num_terminal_cols() - BT_PROMPT_OK_FAIL_STRLEN;
216 }
217
218 for (int i = 0; i < offset; i++)
219 putchar(' ');
9b0a0ba9
OZ
220
221 const char *result_str = is_terminal ? BT_PROMPT_OK : BT_PROMPT_OK_NO_COLOR;
5e3cd0e5 222 if (!result)
9b0a0ba9
OZ
223 result_str = is_terminal ? BT_PROMPT_FAIL : BT_PROMPT_FAIL_NO_COLOR;
224
fa71b268 225 printf("%s\n", result_str);
d348a916
MM
226
227 if (do_die && !result)
228 abort();
9b0a0ba9
OZ
229}
230
231/**
232 * bt_log_overall_result - pretty print of suite case result
5e3cd0e5 233 * @result: 1 or 0
9b0a0ba9
OZ
234 * @fmt: a description message (could be long, over more lines)
235 * ...: variable argument list
236 *
237 * This function is used for pretty printing of test suite case result.
238 */
239static void
240bt_log_overall_result(int result, const char *fmt, ...)
241{
242 va_list argptr;
243 va_start(argptr, fmt);
244 bt_log_result(result, fmt, argptr);
245 va_end(argptr);
246}
247
248/**
249 * bt_log_suite_result - pretty print of suite case result
5e3cd0e5 250 * @result: 1 or 0
9b0a0ba9
OZ
251 * @fmt: a description message (could be long, over more lines)
252 * ...: variable argument list
253 *
254 * This function is used for pretty printing of test suite case result.
255 */
256void
257bt_log_suite_result(int result, const char *fmt, ...)
258{
5e3cd0e5 259 if(bt_verbose >= BT_VERBOSE_SUITE || !result)
9b0a0ba9
OZ
260 {
261 va_list argptr;
262 va_start(argptr, fmt);
263 bt_log_result(result, fmt, argptr);
264 va_end(argptr);
265 }
266}
267
268/**
269 * bt_log_suite_case_result - pretty print of suite result
5e3cd0e5 270 * @result: 1 or 0
9b0a0ba9
OZ
271 * @fmt: a description message (could be long, over more lines)
272 * ...: variable argument list
273 *
274 * This function is used for pretty printing of test suite result.
275 */
276void
277bt_log_suite_case_result(int result, const char *fmt, ...)
278{
279 if(bt_verbose >= BT_VERBOSE_SUITE_CASE)
280 {
281 va_list argptr;
282 va_start(argptr, fmt);
283 bt_log_result(result, fmt, argptr);
284 va_end(argptr);
285 }
286}
287
288int
289bt_test_suite_base(int (*fn)(const void *), const char *id, const void *fn_arg, int forked, int timeout, const char *dsc, ...)
290{
291 if (list_tests)
292 {
293 printf("%28s - ", id);
294 va_list args;
295 va_start(args, dsc);
296 vprintf(dsc, args);
297 va_end(args);
298 printf("\n");
5e3cd0e5 299 return 1;
9b0a0ba9
OZ
300 }
301
302 if (no_fork)
303 forked = 0;
304
305 if (no_timeout)
306 timeout = 0;
307
308 if (request && strcmp(id, request))
5e3cd0e5 309 return 1;
9b0a0ba9 310
5e3cd0e5 311 bt_suite_result = 1;
9b0a0ba9
OZ
312 bt_test_id = id;
313
314 if (bt_verbose >= BT_VERBOSE_ABSOLUTELY_ALL)
315 bt_log("Starting");
316
317 if (!forked)
318 {
319 bt_suite_result = bt_run_test_fn(fn, fn_arg, timeout);
320 }
321 else
322 {
323 pid_t pid = fork();
324 bt_syscall(pid < 0, "fork");
325
326 if (pid == 0)
327 {
328 /* child of fork */
329 _exit(bt_run_test_fn(fn, fn_arg, timeout));
330 }
331
332 int s;
333 int rv = waitpid(pid, &s, 0);
334 bt_syscall(rv < 0, "waitpid");
335
336 if (WIFEXITED(s))
337 {
338 /* Normal exit */
339 bt_suite_result = WEXITSTATUS(s);
340 }
341 else if (WIFSIGNALED(s))
342 {
343 /* Stopped by signal */
5e3cd0e5 344 bt_suite_result = 0;
9b0a0ba9
OZ
345
346 int sn = WTERMSIG(s);
347 if (sn == SIGALRM)
348 {
349 bt_log("Timeout expired");
350 }
351 else if (sn == SIGSEGV)
352 {
353 bt_log("Segmentation fault");
354 bt_dump_backtrace();
355 }
356 else if (sn != SIGABRT)
357 bt_log("Signal %d received", sn);
358 }
359
360 if (WCOREDUMP(s) && bt_verbose)
361 bt_log("Core dumped");
362 }
363
5e3cd0e5
PT
364 if (!bt_suite_result)
365 bt_result = 0;
9b0a0ba9
OZ
366
367 bt_log_suite_result(bt_suite_result, NULL);
368 bt_test_id = NULL;
369
370 return bt_suite_result;
371}
372
373int
374bt_exit_value(void)
375{
5e3cd0e5 376 if (!list_tests || (list_tests && !bt_result))
9b0a0ba9 377 bt_log_overall_result(bt_result, "");
5e3cd0e5 378 return bt_result ? EXIT_SUCCESS : EXIT_FAILURE;
9b0a0ba9
OZ
379}
380
381/**
382 * bt_assert_batch__ - test a batch of inputs/outputs tests
383 * @opts: includes all necessary data
384 *
385 * Should be called using macro bt_assert_batch().
5e3cd0e5 386 * Returns 1 or 0.
9b0a0ba9
OZ
387 */
388int
389bt_assert_batch__(struct bt_batch *opts)
390{
391 int i;
392 for (i = 0; i < opts->ndata; i++)
393 {
394 int bt_suit_case_result = opts->test_fn(opts->out_buf, opts->data[i].in, opts->data[i].out);
395
5e3cd0e5
PT
396 if (bt_suit_case_result == 0)
397 bt_suite_result = 0;
9b0a0ba9
OZ
398
399 char b[BT_BUFFER_SIZE];
400 snprintf(b, sizeof(b), "%s(", opts->test_fn_name);
401
402 opts->in_fmt(b+strlen(b), sizeof(b)-strlen(b), opts->data[i].in);
403 sprintf_concat(b, ") gives ");
404 opts->out_fmt(b+strlen(b), sizeof(b)-strlen(b), opts->out_buf);
405
5e3cd0e5 406 if (bt_suit_case_result == 0)
9b0a0ba9
OZ
407 {
408 sprintf_concat(b, ", but expecting is ");
409 opts->out_fmt(b+strlen(b), sizeof(b)-strlen(b), opts->data[i].out);
410 }
411
412 bt_log_suite_case_result(bt_suit_case_result, "%s", b);
413 }
414
415 return bt_suite_result;
416}
417
418/**
419 * bt_fmt_str - formating string into output buffer
420 * @buf: buffer for write
421 * @size: empty size in @buf
422 * @data: null-byte terminated string
423 *
424 * This function can be used with bt_assert_batch() function.
425 * Input @data should be const char * string.
426 */
427void
428bt_fmt_str(char *buf, size_t size, const void *data)
429{
430 const byte *s = data;
431
432 snprintf(buf, size, "\"");
433 while (*s)
434 {
435 snprintf(buf+strlen(buf), size-strlen(buf), bt_is_char(*s) ? "%c" : "\\%03u", *s);
436 s++;
437 }
438 snprintf(buf+strlen(buf), size-strlen(buf), "\"");
439}
440
441/**
442 * bt_fmt_unsigned - formating unsigned int into output buffer
443 * @buf: buffer for write
444 * @size: empty size in @buf
445 * @data: unsigned number
446 *
447 * This function can be used with bt_assert_batch() function.
448 */
449void
450bt_fmt_unsigned(char *buf, size_t size, const void *data)
451{
452 const uint *n = data;
453 snprintf(buf, size, "0x%x (%u)", *n, *n);
454}
455
456/**
457 * bt_fmt_ipa - formating ip_addr into output buffer
458 * @buf: buffer for write
459 * @size: empty size in @buf
460 * @data: should be struct ip_addr *
461 *
462 * This function can be used with bt_assert_batch() function.
463 */
464void
465bt_fmt_ipa(char *buf, size_t size, const void *data)
466{
467 const ip_addr *ip = data;
468 bsnprintf(buf, size, "%I", *ip);
469}
470
471int
472bt_is_char(byte c)
473{
474 return (c >= (byte) 32 && c <= (byte) 126);
475}
476
477/*
478 * Mock-ups of all necessary public functions in main.c
479 */
480
481char *bird_name;
482void async_config(void) {}
483void async_dump(void) {}
484void async_shutdown(void) {}
485void cmd_check_config(char *name UNUSED) {}
486void cmd_reconfig(char *name UNUSED, int type UNUSED, int timeout UNUSED) {}
487void cmd_reconfig_confirm(void) {}
488void cmd_reconfig_undo(void) {}
bdf2e55d 489void cmd_reconfig_status(void) {}
bb57d917 490void cmd_graceful_restart(void) {}
9b0a0ba9
OZ
491void cmd_shutdown(void) {}
492void cmd_reconfig_undo_notify(void) {}
493
494#include "nest/bird.h"
495#include "lib/net.h"
496#include "conf/conf.h"
497void sysdep_preconfig(struct config *c UNUSED) {}
498int sysdep_commit(struct config *new UNUSED, struct config *old UNUSED) { return 0; }
499void sysdep_shutdown_done(void) {}
500
501#include "nest/cli.h"
502int cli_get_command(cli *c UNUSED) { return 0; }
503void cli_write_trigger(cli *c UNUSED) {}
504cli *cmd_reconfig_stored_cli;