From 5bf9890b3b18ad98f5ac601992bc08533ce9e209 Mon Sep 17 00:00:00 2001 From: Steven Murdoch Date: Sun, 24 Jul 2011 23:31:59 +0100 Subject: [PATCH] Test case for reading the partial output of a background process --- src/common/util.c | 14 ++++---- src/common/util.h | 1 + src/test/test-child.c | 4 +++ src/test/test_util.c | 78 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 7 deletions(-) diff --git a/src/common/util.c b/src/common/util.c index e63047b91e..5a5f3b5fbd 100644 --- a/src/common/util.c +++ b/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 diff --git a/src/common/util.h b/src/common/util.h index c111ba72f2..2efe557857 100644 --- a/src/common/util.h +++ b/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, diff --git a/src/test/test-child.c b/src/test/test-child.c index cf49c5d31e..1b9c5e3d57 100644 --- a/src/test/test-child.c +++ b/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 diff --git a/src/test/test_util.c b/src/test/test_util.c index c6dc98dc6b..071fd04e87 100644 --- a/src/test/test_util.c +++ b/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 };