|
@@ -16,6 +16,7 @@
|
|
|
#include "mempool.h"
|
|
|
#endif
|
|
|
#include "memarea.h"
|
|
|
+#include "util_process.h"
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
#include <tchar.h>
|
|
@@ -2538,6 +2539,19 @@ test_util_fgets_eagain(void *ptr)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+#ifndef BUILDDIR
|
|
|
+#define BUILDDIR "."
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef _WIN32
|
|
|
+#define notify_pending_waitpid_callbacks() STMT_NIL
|
|
|
+#define TEST_CHILD "test-child.exe"
|
|
|
+#define EOL "\r\n"
|
|
|
+#else
|
|
|
+#define TEST_CHILD (BUILDDIR "/src/test/test-child")
|
|
|
+#define EOL "\n"
|
|
|
+#endif
|
|
|
+
|
|
|
|
|
|
static void
|
|
|
run_util_spawn_background(const char *argv[], const char *expected_out,
|
|
@@ -2557,19 +2571,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
|
|
|
|
|
|
|
|
@@ -2580,12 +2603,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();
|
|
|
+
|
|
|
|
|
|
retval = tor_get_exit_code(process_handle, 1, &exit_code);
|
|
|
test_eq(PROCESS_EXIT_EXITED, retval);
|
|
|
test_eq(expected_exit, exit_code);
|
|
|
|
|
|
|
|
|
+#ifndef _WIN32
|
|
|
+ notify_pending_waitpid_callbacks();
|
|
|
+ tt_ptr_op(process_handle->waitpid_cb, ==, NULL);
|
|
|
+#endif
|
|
|
+
|
|
|
|
|
|
pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
|
|
|
sizeof(stderr_buf) - 1);
|
|
@@ -2594,6 +2624,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);
|
|
@@ -2603,29 +2635,20 @@ run_util_spawn_background(const char *argv[], const char *expected_out,
|
|
|
static void
|
|
|
test_util_spawn_background_ok(void *ptr)
|
|
|
{
|
|
|
-#ifdef _WIN32
|
|
|
- const char *argv[] = {"test-child.exe", "--test", NULL};
|
|
|
- const char *expected_out = "OUT\r\n--test\r\nSLEEPING\r\nDONE\r\n";
|
|
|
- const char *expected_err = "ERR\r\n";
|
|
|
-#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\n";
|
|
|
-#endif
|
|
|
+ const char *argv[] = {TEST_CHILD, "--test", NULL};
|
|
|
+ const char *expected_out = "OUT"EOL "--test"EOL "SLEEPING"EOL "DONE" EOL;
|
|
|
+ const char *expected_err = "ERR"EOL;
|
|
|
|
|
|
(void)ptr;
|
|
|
|
|
|
run_util_spawn_background(argv, expected_out, expected_err, 0,
|
|
|
- PROCESS_STATUS_RUNNING);
|
|
|
+ PROCESS_STATUS_RUNNING);
|
|
|
}
|
|
|
|
|
|
|
|
|
static void
|
|
|
test_util_spawn_background_fail(void *ptr)
|
|
|
{
|
|
|
-#ifndef BUILDDIR
|
|
|
-#define BUILDDIR "."
|
|
|
-#endif
|
|
|
const char *argv[] = {BUILDDIR "/src/test/no-such-file", "--test", NULL};
|
|
|
const char *expected_err = "";
|
|
|
char expected_out[1024];
|
|
@@ -2646,13 +2669,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);
|
|
|
}
|
|
|
|
|
|
|
|
|
* 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;
|
|
@@ -2662,22 +2685,22 @@ test_util_spawn_background_partial_read(void *ptr)
|
|
|
process_handle_t *process_handle=NULL;
|
|
|
int status;
|
|
|
char stdout_buf[100], stderr_buf[100];
|
|
|
-#ifdef _WIN32
|
|
|
- const char *argv[] = {"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";
|
|
|
-#else
|
|
|
- const char *argv[] = {BUILDDIR "/src/test/test-child", "--test", NULL};
|
|
|
- const char *expected_out[] = { "OUT\n--test\nSLEEPING\n",
|
|
|
- "DONE\n",
|
|
|
+
|
|
|
+ const char *argv[] = {TEST_CHILD, "--test", NULL};
|
|
|
+ const char *expected_out[] = { "OUT" EOL "--test" EOL "SLEEPING" EOL,
|
|
|
+ "DONE" EOL,
|
|
|
NULL };
|
|
|
- const char *expected_err = "ERR\n";
|
|
|
+ const char *expected_err = "ERR" EOL;
|
|
|
+
|
|
|
+#ifndef _WIN32
|
|
|
int eof = 0;
|
|
|
#endif
|
|
|
int expected_out_ctr;
|
|
|
- (void)ptr;
|
|
|
+
|
|
|
+ if (exit_early) {
|
|
|
+ argv[1] = "--hang";
|
|
|
+ expected_out[0] = "OUT"EOL "--hang"EOL "SLEEPING" EOL;
|
|
|
+ }
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
@@ -2713,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;
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
|
|
@@ -2750,6 +2779,75 @@ 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;
|
|
|
+
|
|
|
+ const char *argv[] = {TEST_CHILD, "--fast", NULL};
|
|
|
+
|
|
|
+ (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 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);
|
|
|
+}
|
|
|
+
|
|
|
+#undef TEST_CHILD
|
|
|
+#undef EOL
|
|
|
+
|
|
|
|
|
|
* Test for format_hex_number_sigsafe()
|
|
|
*/
|
|
@@ -3695,6 +3793,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),
|