mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 12:23:32 +01:00
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.
This commit is contained in:
parent
e2e588175e
commit
e3833193af
@ -9,6 +9,13 @@
|
|||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#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
|
/** Trivial test program which prints out its command line arguments so we can
|
||||||
* check if tor_spawn_background() works */
|
* check if tor_spawn_background() works */
|
||||||
@ -16,27 +23,38 @@ int
|
|||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int i;
|
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(stdout, "OUT\n");
|
||||||
fprintf(stderr, "ERR\n");
|
fprintf(stderr, "ERR\n");
|
||||||
for (i = 1; i < argc; i++)
|
for (i = 1; i < argc; i++)
|
||||||
fprintf(stdout, "%s\n", argv[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()
|
/* We need to flush stdout so that test_util_spawn_background_partial_read()
|
||||||
succeed. Otherwise ReadFile() will get the entire output in one */
|
succeed. Otherwise ReadFile() will get the entire output in one */
|
||||||
// XXX: Can we make stdio flush on newline?
|
// XXX: Can we make stdio flush on newline?
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
#ifdef _WIN32
|
if (!fast)
|
||||||
Sleep(1000);
|
SLEEP(1);
|
||||||
#else
|
|
||||||
sleep(1);
|
|
||||||
#endif
|
|
||||||
fprintf(stdout, "DONE\n");
|
fprintf(stdout, "DONE\n");
|
||||||
#ifdef _WIN32
|
fflush(stdout);
|
||||||
Sleep(1000);
|
if (fast)
|
||||||
#else
|
return 0;
|
||||||
sleep(1);
|
|
||||||
#endif
|
while (--delay) {
|
||||||
|
SLEEP(1);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "test.h"
|
#include "test.h"
|
||||||
#include "mempool.h"
|
#include "mempool.h"
|
||||||
#include "memarea.h"
|
#include "memarea.h"
|
||||||
|
#include "util_process.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
@ -2529,6 +2530,10 @@ test_util_fgets_eagain(void *ptr)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define notify_pending_waitpid_callbacks() STMT_NIL
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Helper function for testing tor_spawn_background */
|
/** Helper function for testing tor_spawn_background */
|
||||||
static void
|
static void
|
||||||
run_util_spawn_background(const char *argv[], const char *expected_out,
|
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);
|
status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
notify_pending_waitpid_callbacks();
|
||||||
|
|
||||||
test_eq(expected_status, status);
|
test_eq(expected_status, status);
|
||||||
if (status == PROCESS_STATUS_ERROR)
|
if (status == PROCESS_STATUS_ERROR) {
|
||||||
|
tt_ptr_op(process_handle, ==, NULL);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
test_assert(process_handle != NULL);
|
test_assert(process_handle != NULL);
|
||||||
test_eq(expected_status, process_handle->status);
|
test_eq(expected_status, process_handle->status);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
notify_pending_waitpid_callbacks();
|
||||||
|
tt_ptr_op(process_handle->waitpid_cb, !=, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
test_assert(process_handle->stdout_pipe != INVALID_HANDLE_VALUE);
|
test_assert(process_handle->stdout_pipe != INVALID_HANDLE_VALUE);
|
||||||
test_assert(process_handle->stderr_pipe != INVALID_HANDLE_VALUE);
|
test_assert(process_handle->stderr_pipe != INVALID_HANDLE_VALUE);
|
||||||
#else
|
#else
|
||||||
test_assert(process_handle->stdout_pipe > 0);
|
test_assert(process_handle->stdout_pipe >= 0);
|
||||||
test_assert(process_handle->stderr_pipe > 0);
|
test_assert(process_handle->stderr_pipe >= 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Check stdout */
|
/* Check stdout */
|
||||||
@ -2571,12 +2585,19 @@ run_util_spawn_background(const char *argv[], const char *expected_out,
|
|||||||
test_eq(strlen(expected_out), pos);
|
test_eq(strlen(expected_out), pos);
|
||||||
test_streq(expected_out, stdout_buf);
|
test_streq(expected_out, stdout_buf);
|
||||||
|
|
||||||
|
notify_pending_waitpid_callbacks();
|
||||||
|
|
||||||
/* Check it terminated correctly */
|
/* Check it terminated correctly */
|
||||||
retval = tor_get_exit_code(process_handle, 1, &exit_code);
|
retval = tor_get_exit_code(process_handle, 1, &exit_code);
|
||||||
test_eq(PROCESS_EXIT_EXITED, retval);
|
test_eq(PROCESS_EXIT_EXITED, retval);
|
||||||
test_eq(expected_exit, exit_code);
|
test_eq(expected_exit, exit_code);
|
||||||
// TODO: Make test-child exit with something other than 0
|
// 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 */
|
/* Check stderr */
|
||||||
pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
|
pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
|
||||||
sizeof(stderr_buf) - 1);
|
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_streq(expected_err, stderr_buf);
|
||||||
test_eq(strlen(expected_err), pos);
|
test_eq(strlen(expected_err), pos);
|
||||||
|
|
||||||
|
notify_pending_waitpid_callbacks();
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (process_handle)
|
if (process_handle)
|
||||||
tor_process_handle_destroy(process_handle, 1);
|
tor_process_handle_destroy(process_handle, 1);
|
||||||
@ -2607,7 +2630,7 @@ test_util_spawn_background_ok(void *ptr)
|
|||||||
(void)ptr;
|
(void)ptr;
|
||||||
|
|
||||||
run_util_spawn_background(argv, expected_out, expected_err, 0,
|
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 */
|
/** 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);
|
"ERR: Failed to spawn background process - code %s\n", code);
|
||||||
|
|
||||||
run_util_spawn_background(argv, expected_out, expected_err, 255,
|
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
|
/** Test that reading from a handle returns a partial read rather than
|
||||||
* blocking */
|
* blocking */
|
||||||
static void
|
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_exit = 0;
|
||||||
const int expected_status = PROCESS_STATUS_RUNNING;
|
const int expected_status = PROCESS_STATUS_RUNNING;
|
||||||
@ -2668,7 +2691,16 @@ test_util_spawn_background_partial_read(void *ptr)
|
|||||||
int eof = 0;
|
int eof = 0;
|
||||||
#endif
|
#endif
|
||||||
int expected_out_ctr;
|
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 */
|
/* Start the program */
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -2704,6 +2736,12 @@ test_util_spawn_background_partial_read(void *ptr)
|
|||||||
expected_out_ctr++;
|
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 */
|
/* The process should have exited without writing more */
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
|
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);
|
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()
|
* 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_ok, 0),
|
||||||
UTIL_TEST(spawn_background_fail, 0),
|
UTIL_TEST(spawn_background_fail, 0),
|
||||||
UTIL_TEST(spawn_background_partial_read, 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_hex_number, 0),
|
||||||
UTIL_TEST(format_dec_number, 0),
|
UTIL_TEST(format_dec_number, 0),
|
||||||
UTIL_TEST(join_win_cmdline, 0),
|
UTIL_TEST(join_win_cmdline, 0),
|
||||||
|
Loading…
Reference in New Issue
Block a user