Browse Source

Test case for reading the partial output of a background process

Steven Murdoch 12 years ago
parent
commit
5bf9890b3b
4 changed files with 90 additions and 7 deletions
  1. 7 7
      src/common/util.c
  2. 1 0
      src/common/util.h
  3. 4 0
      src/test/test-child.c
  4. 78 0
      src/test/test_util.c

+ 7 - 7
src/common/util.c

@@ -3292,8 +3292,8 @@ tor_get_exit_code(const process_handle_t process_handle)
 
 #ifdef MS_WINDOWS
 /* Windows equivalent of read_all */
-static ssize_t
-read_all_handle(HANDLE h, char *buf, size_t count, HANDLE hProcess)
+ssize_t
+tor_read_all_handle(HANDLE h, char *buf, size_t count, HANDLE hProcess)
 {
   size_t numread = 0;
   BOOL retval;
@@ -3310,7 +3310,7 @@ read_all_handle(HANDLE h, char *buf, size_t count, HANDLE hProcess)
         "Failed to peek from handle: %s",
         format_win32_error(GetLastError()));
       return -1;
-    } else if (0 == byte_count) 
+    } else if (0 == byte_count) {
       /* Nothing available: process exited or it is busy */
 
       /* Exit if we don't know whether the process is running */
@@ -3352,8 +3352,8 @@ tor_read_all_from_process_stdout(const process_handle_t process_handle,
                                 char *buf, size_t count)
 {
 #ifdef MS_WINDOWS
-  return read_all_handle(process_handle.stdout_pipe, buf, count,
-                         process_handle.pid.hProcess);
+  return tor_read_all_handle(process_handle.stdout_pipe, buf, count,
+                             process_handle.pid.hProcess);
 #else
   return read_all(process_handle.stdout_pipe, buf, count, 0);
 #endif
@@ -3364,8 +3364,8 @@ tor_read_all_from_process_stderr(const process_handle_t process_handle,
                                  char *buf, size_t count)
 {
 #ifdef MS_WINDOWS
-  return read_all_handle(process_handle.stderr_pipe, buf, count,
-                         process_handle.pid.hProcess);
+  return tor_read_all_handle(process_handle.stderr_pipe, buf, count,
+                             process_handle.pid.hProcess);
 #else
   return read_all(process_handle.stderr_pipe, buf, count, 0);
 #endif

+ 1 - 0
src/common/util.h

@@ -364,6 +364,7 @@ typedef struct process_handle_s {
 process_handle_t tor_spawn_background(const char *const filename,
                                       const char **argv);
 int tor_get_exit_code(const process_handle_t pid);
+ssize_t tor_read_all_handle(HANDLE h, char *buf, size_t count, HANDLE hProcess);
 ssize_t tor_read_all_from_process_stdout(const process_handle_t process_handle,
                                         char *buf, size_t count);
 ssize_t tor_read_all_from_process_stderr(const process_handle_t process_handle,

+ 4 - 0
src/test/test-child.c

@@ -19,6 +19,10 @@ main(int argc, char **argv)
   for (i = 1; i < argc; i++)
     fprintf(stdout, "%s\n", argv[i]);
   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 MS_WINDOWS
   Sleep(1000);
 #else

+ 78 - 0
src/test/test_util.c

@@ -1468,6 +1468,83 @@ test_util_spawn_background_fail(void *ptr)
   run_util_spawn_background(argv, expected_out, expected_err, 255, expected_status);
 }
 
+/** Helper function for testing tor_spawn_background */
+static void
+test_util_spawn_background_partial_read(void *ptr)
+{
+#ifdef MS_WINDOWS
+  // TODO: Under MSYS, BUILDDIR in orconfig.h needs to be tweaked
+  const char *argv[] = {BUILDDIR "/src/test/test-child.exe", "--test", NULL};
+  const char *expected_out[] = { "OUT\r\n--test\r\nSLEEPING\r\n",
+                                 "DONE\r\n",
+                                 NULL };
+  const char *expected_err = "ERR\r\n";
+  int expected_out_ctr;
+#else
+  const char *argv[] = {BUILDDIR "/src/test/test-child", "--test", NULL};
+  const char *expected_out = "OUT\n--test\nSLEEPING\nDONE\n";
+  const char *expected_err = "ERR\r\n";
+#endif
+  const int expected_exit = 0;
+  const int expected_status = 0;
+
+  int retval;
+  ssize_t pos;
+  process_handle_t process_handle;
+  char stdout_buf[100], stderr_buf[100];
+
+  /* Start the program */
+  process_handle = tor_spawn_background(argv[0], argv);
+  tt_int_op(process_handle.status, ==, expected_status);
+
+  /* Check stdout */
+#ifdef MS_WINDOWS
+  for (expected_out_ctr =0; expected_out[expected_out_ctr] != NULL;) {
+    pos = tor_read_all_handle(process_handle.stdout_pipe, stdout_buf,
+                              sizeof(stdout_buf) - 1, NULL);
+    log_info(LD_GENERAL, "tor_read_all_handle() returned %d", (int)pos);
+
+    /* We would have blocked, keep on trying */
+    if (0 == pos)
+      continue;
+
+    tt_assert(pos >= 0);
+    stdout_buf[pos] = '\0';
+    tt_str_op(stdout_buf, ==, expected_out[expected_out_ctr]);
+    tt_int_op(pos, ==, strlen(expected_out[expected_out_ctr]));
+    expected_out_ctr++;
+  }
+  /* The process should have exited without writing more */
+  pos = tor_read_all_handle(process_handle.stdout_pipe, stdout_buf,
+                            sizeof(stdout_buf) - 1,
+                            process_handle.pid.hProcess);
+  tt_int_op(pos, ==, 0);
+#else
+  pos = tor_read_all_from_process_stdout(process_handle, stdout_buf,
+                                         sizeof(stdout_buf) - 1);
+  tt_assert(pos >= 0);
+  stdout_buf[pos] = '\0';
+  tt_str_op(stdout_buf, ==, expected_out);
+  tt_int_op(pos, ==, strlen(expected_out));
+#endif
+
+  /* Check it terminated correctly */
+  retval = tor_get_exit_code(process_handle);
+  tt_int_op(retval, ==, expected_exit);
+  // TODO: Make test-child exit with something other than 0
+
+  /* Check stderr */
+  pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
+                                         sizeof(stderr_buf) - 1);
+  tt_assert(pos >= 0);
+  stderr_buf[pos] = '\0';
+  tt_str_op(stderr_buf, ==, expected_err);
+  tt_int_op(pos, ==, strlen(expected_err));
+
+ done:
+  ;
+}
+
 static void
 test_util_di_ops(void)
 {
@@ -1555,6 +1632,7 @@ struct testcase_t util_tests[] = {
 #endif
   UTIL_TEST(spawn_background_ok, 0),
   UTIL_TEST(spawn_background_fail, 0),
+  UTIL_TEST(spawn_background_partial_read, 0),
   END_OF_TESTCASES
 };