tests: add failsafe timeout for tests running in fork mode
authorMike Blumenkrantz <zmike@samsung.com>
Mon, 30 Jul 2018 16:50:58 +0000 (12:50 -0400)
committerWoochanlee <wc0917.lee@samsung.com>
Thu, 23 Aug 2018 06:40:59 +0000 (15:40 +0900)
some tests manage to deadlock themselves on travis, seemingly due to some
hard to reproduce issues which are a result of the extremely low amount of
resources available on travis builds

this adds a simple 'timeout' process which does nothing but sleep(60);
and then returns. the exiting of this process will cause the main test
process to break out of the deadlock and then exit instead of timing out
a ci build

Differential Revision: https://phab.enlightenment.org/D6697

src/Makefile.am
src/tests/.gitignore
src/tests/efl_check.h
src/tests/timeout.c [new file with mode: 0644]

index c5ca05d..32de340 100644 (file)
@@ -145,6 +145,10 @@ endif
 DIST_SUBDIRS += $(EXAMPLES_SUBDIRS)
 
 if EFL_ENABLE_TESTS
+noinst_PROGRAMS += tests/timeout
+
+$(check_PROGRAMS): tests/timeout
+
 check-build: all
        @$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
 endif
index 9b233a4..db7ce40 100644 (file)
@@ -4,3 +4,4 @@ check-results*.xml
 *_suite.trs
 *.node
 */cxx_compile_test
+/timeout
index e3218cc..b61bcbb 100644 (file)
 #include <sys/time.h>
 
 #ifdef HAVE_FORK
-#include <sys/types.h>
-#include <sys/wait.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#include <signal.h>
 #include <Eina.h>
 #endif
 
@@ -55,6 +60,8 @@ struct _Efl_Test_Case
    void (*build)(TCase *tc);
 };
 
+static int timeout_pid = 0;
+
 static void
 _efl_tests_list(const Efl_Test_Case *etc)
 {
@@ -247,15 +254,18 @@ _efl_suite_run_end(SRunner *sr, const char *name)
 
 #ifdef HAVE_FORK
 EINA_UNUSED static int
-_efl_suite_wait_on_fork(int *num_forks)
+_efl_suite_wait_on_fork(int *num_forks, Eina_Bool *timeout)
 {
-   int status = 0, ret;
-   waitpid(0, &status, 0);
+   int status = 0, ret, pid;
+   pid = waitpid(0, &status, 0);
    if (WIFEXITED(status))
      ret = WEXITSTATUS(status);
    else
      ret = 1;
-   (*num_forks)--;
+   if (pid == timeout_pid)
+     *timeout = EINA_TRUE;
+   else
+     (*num_forks)--;
    return ret;
 }
 #endif
@@ -270,6 +280,7 @@ _efl_suite_build_and_run(int argc, const char **argv, const char *suite_name, co
    int do_fork;
    int num_forks = 0;
    int can_fork = 0;
+   Eina_Bool timeout_reached = EINA_FALSE;
 #ifdef ENABLE_TIMING_INFO
    double tstart, tcstart;
    int timing = _timing_enabled();
@@ -293,8 +304,15 @@ _efl_suite_build_and_run(int argc, const char **argv, const char *suite_name, co
 #ifdef HAVE_FORK
         if (do_fork && can_fork)
           {
+             if (!timeout_pid)
+               {
+                  timeout_pid = fork();
+                  if (!timeout_pid)
+                    execl("/bin/sh", "/bin/sh", "-c", PACKAGE_BUILD_DIR "/src/tests/timeout", (char *)NULL);
+               }
              if (num_forks == eina_cpu_count())
-               failed_count += _efl_suite_wait_on_fork(&num_forks);
+               failed_count += _efl_suite_wait_on_fork(&num_forks, &timeout_reached);
+             if (timeout_reached) break;
              pid = fork();
              if (pid > 0)
                {
@@ -333,17 +351,32 @@ _efl_suite_build_and_run(int argc, const char **argv, const char *suite_name, co
      }
 
 #ifdef HAVE_FORK
-   if (num_forks)
+   if (num_forks && (!timeout_reached))
      {
         do
           {
-             failed_count += _efl_suite_wait_on_fork(&num_forks);
-          } while (num_forks);
+             failed_count += _efl_suite_wait_on_fork(&num_forks, &timeout_reached);
+          } while (num_forks && (!timeout_reached));
+        if (timeout_reached)
+          {
+             timeout_pid = 0;
+             printf("FAILSAFE TIMEOUT REACHED!\n");
+             fflush(stdout);
+             failed_count++;
+          }
      }
    else
 #endif
      failed_count = _efl_suite_run_end(sr, NULL);
 
+#ifdef HAVE_FORK
+   if (timeout_pid)
+     {
+        kill(timeout_pid, SIGKILL);
+        timeout_pid = 0;
+     }
+#endif
+
 #ifdef ENABLE_TIMING_INFO
    if (timing)
      {
diff --git a/src/tests/timeout.c b/src/tests/timeout.c
new file mode 100644 (file)
index 0000000..de88153
--- /dev/null
@@ -0,0 +1,15 @@
+#include <unistd.h>
+
+#if defined(__clang__)
+# pragma clang diagnostic ignored "-Wunused-parameter"
+#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4
+# pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+
+int
+main(int arc, char *argv[])
+{
+   sleep(60);
+   return 0;
+}