[tor-commits] [tor/master] More unit tests for process spawning

nickm at torproject.org nickm at torproject.org
Sat Jun 14 15:47:50 UTC 2014


commit e3833193af11dc4252e90565c3919889cc4130b3
Author: Nick Mathewson <nickm at torproject.org>
Date:   Wed Apr 30 12:50:00 2014 -0400

    More unit tests for process spawning
    
    Try killing a running process; try noticing that a process has
    exited without checking its output; verify that waitpid_cb (when
    present) is set to NULL when you would expect it to be.
---
 src/test/test-child.c |   40 +++++++++++-----
 src/test/test_util.c  |  124 ++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 146 insertions(+), 18 deletions(-)

diff --git a/src/test/test-child.c b/src/test/test-child.c
index ef10fbb..756782e 100644
--- a/src/test/test-child.c
+++ b/src/test/test-child.c
@@ -9,6 +9,13 @@
 #else
 #include <unistd.h>
 #endif
+#include <string.h>
+
+#ifdef _WIN32
+#define SLEEP(sec) Sleep((sec)*1000)
+#else
+#define SLEEP(sec) sleep(sec)
+#endif
 
 /** Trivial test program which prints out its command line arguments so we can
  * check if tor_spawn_background() works */
@@ -16,27 +23,38 @@ int
 main(int argc, char **argv)
 {
   int i;
+  int delay = 1;
+  int fast = 0;
+
+  if (argc > 1)  {
+    if (!strcmp(argv[1], "--hang")) {
+      delay = 60;
+    } else if (!strcmp(argv[1], "--fast")) {
+      fast = 1;
+      delay = 0;
+    }
+  }
 
   fprintf(stdout, "OUT\n");
   fprintf(stderr, "ERR\n");
   for (i = 1; i < argc; i++)
     fprintf(stdout, "%s\n", argv[i]);
-  fprintf(stdout, "SLEEPING\n");
+  if (!fast)
+    fprintf(stdout, "SLEEPING\n");
   /* We need to flush stdout so that test_util_spawn_background_partial_read()
      succeed. Otherwise ReadFile() will get the entire output in one */
   // XXX: Can we make stdio flush on newline?
   fflush(stdout);
-#ifdef _WIN32
-  Sleep(1000);
-#else
-  sleep(1);
-#endif
+  if (!fast)
+    SLEEP(1);
   fprintf(stdout, "DONE\n");
-#ifdef _WIN32
-  Sleep(1000);
-#else
-  sleep(1);
-#endif
+  fflush(stdout);
+  if (fast)
+    return 0;
+
+  while (--delay) {
+    SLEEP(1);
+  }
 
   return 0;
 }
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 6d6b6db..029e88e 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -14,6 +14,7 @@
 #include "test.h"
 #include "mempool.h"
 #include "memarea.h"
+#include "util_process.h"
 
 #ifdef _WIN32
 #include <tchar.h>
@@ -2529,6 +2530,10 @@ test_util_fgets_eagain(void *ptr)
 }
 #endif
 
+#ifdef _WIN32
+#define notify_pending_waitpid_callbacks() STMT_NIL
+#endif
+
 /** Helper function for testing tor_spawn_background */
 static void
 run_util_spawn_background(const char *argv[], const char *expected_out,
@@ -2548,19 +2553,28 @@ run_util_spawn_background(const char *argv[], const char *expected_out,
   status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
 #endif
 
+  notify_pending_waitpid_callbacks();
+
   test_eq(expected_status, status);
-  if (status == PROCESS_STATUS_ERROR)
+  if (status == PROCESS_STATUS_ERROR) {
+    tt_ptr_op(process_handle, ==, NULL);
     return;
+  }
 
   test_assert(process_handle != NULL);
   test_eq(expected_status, process_handle->status);
 
+#ifndef _WIN32
+  notify_pending_waitpid_callbacks();
+  tt_ptr_op(process_handle->waitpid_cb, !=, NULL);
+#endif
+
 #ifdef _WIN32
   test_assert(process_handle->stdout_pipe != INVALID_HANDLE_VALUE);
   test_assert(process_handle->stderr_pipe != INVALID_HANDLE_VALUE);
 #else
-  test_assert(process_handle->stdout_pipe > 0);
-  test_assert(process_handle->stderr_pipe > 0);
+  test_assert(process_handle->stdout_pipe >= 0);
+  test_assert(process_handle->stderr_pipe >= 0);
 #endif
 
   /* Check stdout */
@@ -2571,12 +2585,19 @@ run_util_spawn_background(const char *argv[], const char *expected_out,
   test_eq(strlen(expected_out), pos);
   test_streq(expected_out, stdout_buf);
 
+  notify_pending_waitpid_callbacks();
+
   /* Check it terminated correctly */
   retval = tor_get_exit_code(process_handle, 1, &exit_code);
   test_eq(PROCESS_EXIT_EXITED, retval);
   test_eq(expected_exit, exit_code);
   // TODO: Make test-child exit with something other than 0
 
+#ifndef _WIN32
+  notify_pending_waitpid_callbacks();
+  tt_ptr_op(process_handle->waitpid_cb, ==, NULL);
+#endif
+
   /* Check stderr */
   pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
                                          sizeof(stderr_buf) - 1);
@@ -2585,6 +2606,8 @@ run_util_spawn_background(const char *argv[], const char *expected_out,
   test_streq(expected_err, stderr_buf);
   test_eq(strlen(expected_err), pos);
 
+  notify_pending_waitpid_callbacks();
+
  done:
   if (process_handle)
     tor_process_handle_destroy(process_handle, 1);
@@ -2607,7 +2630,7 @@ test_util_spawn_background_ok(void *ptr)
   (void)ptr;
 
   run_util_spawn_background(argv, expected_out, expected_err, 0,
-                            PROCESS_STATUS_RUNNING);
+      PROCESS_STATUS_RUNNING);
 }
 
 /** Check that failing to find the executable works as expected */
@@ -2637,13 +2660,13 @@ test_util_spawn_background_fail(void *ptr)
     "ERR: Failed to spawn background process - code %s\n", code);
 
   run_util_spawn_background(argv, expected_out, expected_err, 255,
-                            expected_status);
+      expected_status);
 }
 
 /** Test that reading from a handle returns a partial read rather than
  * blocking */
 static void
-test_util_spawn_background_partial_read(void *ptr)
+test_util_spawn_background_partial_read_impl(int exit_early)
 {
   const int expected_exit = 0;
   const int expected_status = PROCESS_STATUS_RUNNING;
@@ -2668,7 +2691,16 @@ test_util_spawn_background_partial_read(void *ptr)
   int eof = 0;
 #endif
   int expected_out_ctr;
-  (void)ptr;
+
+
+  if (exit_early) {
+    argv[1] = "--hang";
+#ifdef _WIN32
+    expected_out[0] = "OUT\r\n--hang\r\nSLEEPING\r\n";
+#else
+    expected_out[0] = "OUT\n--hang\nSLEEPING\n";
+#endif
+  }
 
   /* Start the program */
 #ifdef _WIN32
@@ -2704,6 +2736,12 @@ test_util_spawn_background_partial_read(void *ptr)
     expected_out_ctr++;
   }
 
+  if (exit_early) {
+    tor_process_handle_destroy(process_handle, 1);
+    process_handle = NULL;
+    goto done;
+  }
+
   /* The process should have exited without writing more */
 #ifdef _WIN32
   pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
@@ -2741,6 +2779,76 @@ test_util_spawn_background_partial_read(void *ptr)
   tor_process_handle_destroy(process_handle, 1);
 }
 
+static void
+test_util_spawn_background_partial_read(void *arg)
+{
+  (void)arg;
+  test_util_spawn_background_partial_read_impl(0);
+}
+
+static void
+test_util_spawn_background_exit_early(void *arg)
+{
+  (void)arg;
+  test_util_spawn_background_partial_read_impl(1);
+}
+
+static void
+test_util_spawn_background_waitpid_notify(void *arg)
+{
+  int retval, exit_code;
+  process_handle_t *process_handle=NULL;
+  int status;
+  int ms_timer;
+
+#ifdef _WIN32
+  const char *argv[] = {"test-child.exe", "--fast", NULL};
+#else
+  const char *argv[] = {BUILDDIR "/src/test/test-child", "--fast", NULL};
+#endif
+
+  (void) arg;
+
+#ifdef _WIN32
+  status = tor_spawn_background(NULL, argv, NULL, &process_handle);
+#else
+  status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
+#endif
+
+  tt_int_op(status, ==, PROCESS_STATUS_RUNNING);
+  tt_ptr_op(process_handle, !=, NULL);
+
+  /* We're not going to look at the stdout/stderr output this time. Instead,
+   * we're testing whether notify_pending_waitpid_calbacks() can report the
+   * process exit (on unix) and/or whether tor_get_exit_code() can notice it
+   * (on windows) */
+
+#ifndef _WIN32
+  ms_timer = 30*1000;
+  tt_ptr_op(process_handle->waitpid_cb, !=, NULL);
+  while (process_handle->waitpid_cb && ms_timer > 0) {
+    tor_sleep_msec(100);
+    ms_timer -= 100;
+    notify_pending_waitpid_callbacks();
+  }
+  tt_int_op(ms_timer, >, 0);
+  tt_ptr_op(process_handle->waitpid_cb, ==, NULL);
+#endif
+
+  ms_timer = 30*1000;
+  while (((retval = tor_get_exit_code(process_handle, 0, &exit_code))
+                == PROCESS_EXIT_RUNNING) && ms_timer > 0) {
+    tor_sleep_msec(100);
+    ms_timer -= 100;
+  }
+  tt_int_op(ms_timer, >, 0);
+
+  tt_int_op(retval, ==, PROCESS_EXIT_EXITED);
+
+ done:
+  tor_process_handle_destroy(process_handle, 1);
+}
+
 /**
  * Test for format_hex_number_sigsafe()
  */
@@ -3682,6 +3790,8 @@ struct testcase_t util_tests[] = {
   UTIL_TEST(spawn_background_ok, 0),
   UTIL_TEST(spawn_background_fail, 0),
   UTIL_TEST(spawn_background_partial_read, 0),
+  UTIL_TEST(spawn_background_exit_early, 0),
+  UTIL_TEST(spawn_background_waitpid_notify, 0),
   UTIL_TEST(format_hex_number, 0),
   UTIL_TEST(format_dec_number, 0),
   UTIL_TEST(join_win_cmdline, 0),





More information about the tor-commits mailing list