2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "test_suite.h"
26 static char failure_buf
[512];
29 * Source file failure occurred
31 static const char *failure_file
;
34 * Line of source file failure occurred
36 static int failure_line
;
39 * Backtrace of failure, if any
41 static backtrace_t
*failure_backtrace
;
44 * Flag to indicate if a worker thread failed
46 static bool worker_failed
;
49 * Longjump restore point when failing
51 sigjmp_buf test_restore_point_env
;
56 test_suite_t
* test_suite_create(const char *name
)
62 .tcases
= array_create(0, 0),
70 test_case_t
* test_case_create(const char *name
)
76 .functions
= array_create(sizeof(test_function_t
), 0),
77 .fixtures
= array_create(sizeof(test_fixture_t
), 0),
78 .timeout
= TEST_FUNCTION_DEFAULT_TIMEOUT
,
86 void test_case_add_checked_fixture(test_case_t
*tcase
, test_fixture_cb_t setup
,
87 test_fixture_cb_t teardown
)
89 test_fixture_t fixture
= {
93 array_insert(tcase
->fixtures
, -1, &fixture
);
99 void test_case_add_test_name(test_case_t
*tcase
, char *name
,
100 test_function_cb_t cb
, int start
, int end
)
102 test_function_t fun
= {
108 array_insert(tcase
->functions
, -1, &fun
);
114 void test_case_set_timeout(test_case_t
*tcase
, int s
)
122 void test_suite_add_case(test_suite_t
*suite
, test_case_t
*tcase
)
124 array_insert(suite
->tcases
, -1, tcase
);
128 * Main thread performing tests
130 static pthread_t main_thread
;
135 static inline void test_failure()
137 if (pthread_self() == main_thread
)
139 siglongjmp(test_restore_point_env
, 1);
143 pthread_kill(main_thread
, SIGUSR1
);
144 /* terminate thread to prevent it from going wild */
152 void test_fail_vmsg(const char *file
, int line
, char *fmt
, va_list args
)
154 vsnprintf(failure_buf
, sizeof(failure_buf
), fmt
, args
);
164 void test_fail_msg(const char *file
, int line
, char *fmt
, ...)
169 vsnprintf(failure_buf
, sizeof(failure_buf
), fmt
, args
);
180 void test_fail_if_worker_failed()
182 if (pthread_self() == main_thread
&& worker_failed
)
189 * Signal handler catching critical and alarm signals
191 static void test_sighandler(int signal
)
199 /* a different thread failed, abort test at the next opportunity */
200 worker_failed
= TRUE
;
218 if (lib
->leak_detective
)
220 old
= lib
->leak_detective
->set_state(lib
->leak_detective
, FALSE
);
222 failure_backtrace
= backtrace_create(3);
223 if (lib
->leak_detective
)
225 lib
->leak_detective
->set_state(lib
->leak_detective
, old
);
227 test_fail_msg(NULL
, 0, "%s(%d)", signame
, signal
);
228 /* unable to restore a valid context for that thread, terminate */
229 fprintf(stderr
, "\n%s(%d) outside of main thread:\n", signame
, signal
);
230 failure_backtrace
->log(failure_backtrace
, stderr
, TRUE
);
231 fprintf(stderr
, "terminating...\n");
238 void test_setup_handler()
240 struct sigaction action
= {
241 .sa_handler
= test_sighandler
,
244 main_thread
= pthread_self();
246 /* signal handler inherited by all threads */
247 sigaction(SIGSEGV
, &action
, NULL
);
248 sigaction(SIGILL
, &action
, NULL
);
249 sigaction(SIGBUS
, &action
, NULL
);
250 /* ignore ALRM/USR1, these are catched by main thread only */
251 action
.sa_handler
= SIG_IGN
;
252 sigaction(SIGALRM
, &action
, NULL
);
253 sigaction(SIGUSR1
, &action
, NULL
);
259 void test_setup_timeout(int s
)
261 struct sigaction action
= {
262 .sa_handler
= test_sighandler
,
265 /* This called by main thread only. Setup handler for timeout and
266 * failure cross-thread signaling. */
267 sigaction(SIGALRM
, &action
, NULL
);
268 sigaction(SIGUSR1
, &action
, NULL
);
272 worker_failed
= FALSE
;
278 int test_failure_get(char *msg
, int len
, const char **file
)
280 strncpy(msg
, failure_buf
, len
- 1);
282 *file
= failure_file
;
289 backtrace_t
*test_failure_backtrace()
293 bt
= failure_backtrace
;
294 failure_backtrace
= NULL
;