unit-tests: Defer failures by worker threads
authorTobias Brunner <tobias@strongswan.org>
Fri, 9 May 2014 15:42:37 +0000 (17:42 +0200)
committerTobias Brunner <tobias@strongswan.org>
Mon, 19 May 2014 12:06:55 +0000 (14:06 +0200)
In some cases the main thread is not ready to immediately call siglongjmp(),
e.g. if it currently holds a mutex that is later required during
shutdown.

Therefore, we delay handling errors in worker threads until the main
thread performs the next check itself (or the test function ends).

The same issue remains with SIGALRM.

src/libstrongswan/tests/test_suite.c
src/libstrongswan/tests/test_suite.h

index fb40b05..a636d6f 100644 (file)
@@ -41,6 +41,11 @@ static int failure_line;
 static backtrace_t *failure_backtrace;
 
 /**
+ * Flag to indicate if a worker thread failed
+ */
+static bool worker_failed;
+
+/**
  * Longjump restore point when failing
  */
 sigjmp_buf test_restore_point_env;
@@ -170,6 +175,17 @@ void test_fail_msg(const char *file, int line, char *fmt, ...)
 }
 
 /**
+ * See header.
+ */
+void test_fail_if_worker_failed()
+{
+       if (pthread_self() == main_thread && worker_failed)
+       {
+               test_failure();
+       }
+}
+
+/**
  * Signal handler catching critical and alarm signals
  */
 static void test_sighandler(int signal)
@@ -180,8 +196,9 @@ static void test_sighandler(int signal)
        switch (signal)
        {
                case SIGUSR1:
-                       /* a different thread failed, abort test */
-                       return test_failure();
+                       /* a different thread failed, abort test at the next opportunity */
+                       worker_failed = TRUE;
+                       return;
                case SIGSEGV:
                        signame = "SIGSEGV";
                        break;
@@ -251,6 +268,8 @@ void test_setup_timeout(int s)
        sigaction(SIGUSR1, &action, NULL);
 
        alarm(s);
+
+       worker_failed = FALSE;
 }
 
 /**
index 2b1a64c..4bef6ff 100644 (file)
@@ -237,6 +237,12 @@ void test_fail_vmsg(const char *file, int line, char *fmt, va_list args);
 void test_fail_msg(const char *file, int line, char *fmt, ...);
 
 /**
+ * Let a test fail if one of the worker threads has failed (only if called from
+ * the main thread).
+ */
+void test_fail_if_worker_failed();
+
+/**
  * Check if two integers equal, fail test if not
  *
  * @param a                    first integer
@@ -246,6 +252,7 @@ void test_fail_msg(const char *file, int line, char *fmt, ...);
 ({ \
        typeof(a) _a = a; \
        typeof(b) _b = b; \
+       test_fail_if_worker_failed(); \
        if (_a != _b) \
        { \
                test_fail_msg(__FILE__, __LINE__, #a " != " #b " (%d != %d)", _a, _b); \
@@ -262,6 +269,7 @@ void test_fail_msg(const char *file, int line, char *fmt, ...);
 ({ \
        char* _a = (char*)a; \
        char* _b = (char*)b; \
+       test_fail_if_worker_failed(); \
        if (!_a || !_b || !streq(_a, _b)) \
        { \
                test_fail_msg(__FILE__, __LINE__, \
@@ -279,6 +287,7 @@ void test_fail_msg(const char *file, int line, char *fmt, ...);
 ({ \
        chunk_t _a = (chunk_t)a; \
        chunk_t _b = (chunk_t)b; \
+       test_fail_if_worker_failed(); \
        if (_a.len != _b.len || !memeq(a.ptr, b.ptr, a.len)) \
        { \
                test_fail_msg(__FILE__, __LINE__, \
@@ -293,6 +302,7 @@ void test_fail_msg(const char *file, int line, char *fmt, ...);
  */
 #define test_assert(x) \
 ({ \
+       test_fail_if_worker_failed(); \
        if (!(x)) \
        { \
                test_fail_msg(__FILE__, __LINE__, #x); \
@@ -308,6 +318,7 @@ void test_fail_msg(const char *file, int line, char *fmt, ...);
  */
 #define test_assert_msg(x, fmt, ...) \
 ({ \
+       test_fail_if_worker_failed(); \
        if (!(x)) \
        { \
                test_fail_msg(__FILE__, __LINE__, #x ": " fmt, ##__VA_ARGS__); \
@@ -327,6 +338,7 @@ void test_fail_msg(const char *file, int line, char *fmt, ...);
 #define fail(fmt, ...) test_fail_msg(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
 #define fail_if(x, fmt, ...) \
 ({ \
+       test_fail_if_worker_failed(); \
        if (x) \
        { \
                test_fail_msg(__FILE__, __LINE__, #x ": " fmt, ##__VA_ARGS__); \
@@ -341,10 +353,10 @@ void test_fail_msg(const char *file, int line, char *fmt, ...);
 #define tcase_set_timeout test_case_set_timeout
 #define suite_add_tcase test_suite_add_case
 #define START_TEST(name) static void name (int _i) {
-#define END_TEST }
+#define END_TEST test_fail_if_worker_failed(); }
 #define START_SETUP(name) static void name() {
-#define END_SETUP }
+#define END_SETUP test_fail_if_worker_failed(); }
 #define START_TEARDOWN(name) static void name() {
-#define END_TEARDOWN }
+#define END_TEARDOWN test_fail_if_worker_failed(); }
 
 #endif /** TEST_SUITE_H_ @}*/