summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/test-child.c40
-rw-r--r--src/test/test.c11
-rw-r--r--src/test/test_config.c10
-rw-r--r--src/test/test_logging.c2
-rw-r--r--src/test/test_util.c260
5 files changed, 256 insertions, 67 deletions
diff --git a/src/test/test-child.c b/src/test/test-child.c
index ef10fbb922..756782e70b 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.c b/src/test/test.c
index 3f4b95a985..5786f3ca54 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -106,11 +106,18 @@ setup_directory(void)
{
char buf[MAX_PATH];
const char *tmp = buf;
+ const char *extra_backslash = "";
/* If this fails, we're probably screwed anyway */
if (!GetTempPathA(sizeof(buf),buf))
- tmp = "c:\\windows\\temp";
+ tmp = "c:\\windows\\temp\\";
+ if (strcmpend(tmp, "\\")) {
+ /* According to MSDN, it should be impossible for GetTempPath to give us
+ * an answer that doesn't end with \. But let's make sure. */
+ extra_backslash = "\\";
+ }
tor_snprintf(temp_dir, sizeof(temp_dir),
- "%s\\tor_test_%d_%s", tmp, (int)getpid(), rnd32);
+ "%s%stor_test_%d_%s", tmp, extra_backslash,
+ (int)getpid(), rnd32);
r = mkdir(temp_dir);
}
#else
diff --git a/src/test/test_config.c b/src/test/test_config.c
index 94ac4dca13..b35984f761 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -184,7 +184,7 @@ is_private_dir(const char* path)
if (r) {
return 0;
}
-#if !defined (_WIN32) || defined (WINCE)
+#if !defined (_WIN32)
if ((st.st_mode & (S_IFDIR | 0777)) != (S_IFDIR | 0700)) {
return 0;
}
@@ -201,7 +201,7 @@ test_config_check_or_create_data_subdir(void *arg)
char *subpath;
struct stat st;
int r;
-#if !defined (_WIN32) || defined (WINCE)
+#if !defined (_WIN32)
unsigned group_permission;
#endif
(void)arg;
@@ -210,7 +210,7 @@ test_config_check_or_create_data_subdir(void *arg)
datadir = options->DataDirectory = tor_strdup(get_fname("datadir-0"));
subpath = get_datadir_fname(subdir);
-#if defined (_WIN32) && !defined (WINCE)
+#if defined (_WIN32)
tt_int_op(mkdir(options->DataDirectory), ==, 0);
#else
tt_int_op(mkdir(options->DataDirectory, 0700), ==, 0);
@@ -233,7 +233,7 @@ test_config_check_or_create_data_subdir(void *arg)
tt_abort_perror("stat");
}
-#if !defined (_WIN32) || defined (WINCE)
+#if !defined (_WIN32)
group_permission = st.st_mode | 0070;
r = chmod(subpath, group_permission);
@@ -284,7 +284,7 @@ test_config_write_to_data_subdir(void *arg)
datadir = options->DataDirectory = tor_strdup(get_fname("datadir-1"));
filepath = get_datadir_fname2(subdir, fname);
-#if defined (_WIN32) && !defined (WINCE)
+#if defined (_WIN32)
tt_int_op(mkdir(options->DataDirectory), ==, 0);
#else
tt_int_op(mkdir(options->DataDirectory, 0700), ==, 0);
diff --git a/src/test/test_logging.c b/src/test/test_logging.c
index 7e558f83b1..9f57000bea 100644
--- a/src/test/test_logging.c
+++ b/src/test/test_logging.c
@@ -89,7 +89,7 @@ test_sigsafe_err(void *arg)
init_logging();
mark_logs_temp();
- add_file_log(&include_bug, fn);
+ add_file_log(&include_bug, fn, 0);
tor_log_update_sigsafe_err_fds();
close_temp_logs();
diff --git a/src/test/test_util.c b/src/test/test_util.c
index c7fa141188..3a1ebb89a8 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -16,6 +16,7 @@
#include "mempool.h"
#endif /* ENABLE_MEMPOOLS */
#include "memarea.h"
+#include "util_process.h"
#ifdef _WIN32
#include <tchar.h>
@@ -1382,12 +1383,6 @@ test_util_threads(void)
tv.tv_sec=0;
tv.tv_usec=100*1000;
#endif
-#ifndef TOR_IS_MULTITHREADED
- /* Skip this test if we aren't threading. We should be threading most
- * everywhere by now. */
- if (1)
- return;
-#endif
thread_test_mutex_ = tor_mutex_new();
thread_test_start1_ = tor_mutex_new();
thread_test_start2_ = tor_mutex_new();
@@ -2390,6 +2385,54 @@ test_util_parent_dir(void *ptr)
tor_free(cp);
}
+static void
+test_util_ftruncate(void *ptr)
+{
+ char *buf = NULL;
+ const char *fname;
+ int fd = -1;
+ const char *message = "Hello world";
+ const char *message2 = "Hola mundo";
+ struct stat st;
+
+ (void) ptr;
+
+ fname = get_fname("ftruncate");
+
+ fd = tor_open_cloexec(fname, O_WRONLY|O_CREAT, 0600);
+ tt_int_op(fd, >=, 0);
+
+ /* Make the file be there. */
+ tt_int_op(strlen(message), ==, write_all(fd, message, strlen(message), 0));
+ tt_int_op(tor_fd_getpos(fd), ==, strlen(message));
+ tt_int_op(0, ==, fstat(fd, &st));
+ tt_int_op(st.st_size, ==, strlen(message));
+
+ /* Truncate and see if it got truncated */
+ tt_int_op(0, ==, tor_ftruncate(fd));
+ tt_int_op(tor_fd_getpos(fd), ==, 0);
+ tt_int_op(0, ==, fstat(fd, &st));
+ tt_int_op(st.st_size, ==, 0);
+
+ /* Replace, and see if it got replaced */
+ tt_int_op(strlen(message2), ==,
+ write_all(fd, message2, strlen(message2), 0));
+ tt_int_op(tor_fd_getpos(fd), ==, strlen(message2));
+ tt_int_op(0, ==, fstat(fd, &st));
+ tt_int_op(st.st_size, ==, strlen(message2));
+
+ close(fd);
+ fd = -1;
+
+ buf = read_file_to_str(fname, 0, NULL);
+ tt_str_op(message2, ==, buf);
+
+ done:
+ if (fd >= 0)
+ close(fd);
+ tor_free(buf);
+}
+
#ifdef _WIN32
static void
test_util_load_win_lib(void *ptr)
@@ -2452,8 +2495,9 @@ test_util_exit_status(void *ptr)
#endif
#ifndef _WIN32
-/** Check that fgets waits until a full line, and not return a partial line, on
- * a EAGAIN with a non-blocking pipe */
+/* Check that fgets with a non-blocking pipe returns partial lines and sets
+ * EAGAIN, returns full lines and sets no error, and returns NULL on EOF and
+ * sets no error */
static void
test_util_fgets_eagain(void *ptr)
{
@@ -2462,17 +2506,19 @@ test_util_fgets_eagain(void *ptr)
ssize_t retlen;
char *retptr;
FILE *test_stream = NULL;
- char buf[10];
+ char buf[4] = { 0 };
(void)ptr;
+ errno = 0;
+
/* Set up a pipe to test on */
retval = pipe(test_pipe);
- tt_int_op(retval, >=, 0);
+ tt_int_op(retval, ==, 0);
/* Set up the read-end to be non-blocking */
retval = fcntl(test_pipe[0], F_SETFL, O_NONBLOCK);
- tt_int_op(retval, >=, 0);
+ tt_int_op(retval, ==, 0);
/* Open it as a stdio stream */
test_stream = fdopen(test_pipe[0], "r");
@@ -2482,51 +2528,69 @@ test_util_fgets_eagain(void *ptr)
retlen = write(test_pipe[1], "A", 1);
tt_int_op(retlen, ==, 1);
retptr = fgets(buf, sizeof(buf), test_stream);
- tt_want(retptr == NULL);
tt_int_op(errno, ==, EAGAIN);
+ tt_ptr_op(retptr, ==, buf);
+ tt_str_op(buf, ==, "A");
+ errno = 0;
/* Send in the rest */
retlen = write(test_pipe[1], "B\n", 2);
tt_int_op(retlen, ==, 2);
retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_int_op(errno, ==, 0);
tt_ptr_op(retptr, ==, buf);
- tt_str_op(buf, ==, "AB\n");
+ tt_str_op(buf, ==, "B\n");
+ errno = 0;
/* Send in a full line */
retlen = write(test_pipe[1], "CD\n", 3);
tt_int_op(retlen, ==, 3);
retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_int_op(errno, ==, 0);
tt_ptr_op(retptr, ==, buf);
tt_str_op(buf, ==, "CD\n");
+ errno = 0;
/* Send in a partial line */
retlen = write(test_pipe[1], "E", 1);
tt_int_op(retlen, ==, 1);
retptr = fgets(buf, sizeof(buf), test_stream);
- tt_ptr_op(retptr, ==, NULL);
tt_int_op(errno, ==, EAGAIN);
+ tt_ptr_op(retptr, ==, buf);
+ tt_str_op(buf, ==, "E");
+ errno = 0;
/* Send in the rest */
retlen = write(test_pipe[1], "F\n", 2);
tt_int_op(retlen, ==, 2);
retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_int_op(errno, ==, 0);
tt_ptr_op(retptr, ==, buf);
- tt_str_op(buf, ==, "EF\n");
+ tt_str_op(buf, ==, "F\n");
+ errno = 0;
/* Send in a full line and close */
retlen = write(test_pipe[1], "GH", 2);
tt_int_op(retlen, ==, 2);
retval = close(test_pipe[1]);
- test_pipe[1] = -1;
tt_int_op(retval, ==, 0);
+ test_pipe[1] = -1;
retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_int_op(errno, ==, 0);
tt_ptr_op(retptr, ==, buf);
tt_str_op(buf, ==, "GH");
+ errno = 0;
/* Check for EOF */
retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_int_op(errno, ==, 0);
tt_ptr_op(retptr, ==, NULL);
- tt_int_op(feof(test_stream), >, 0);
+ retval = feof(test_stream);
+ tt_int_op(retval, !=, 0);
+ errno = 0;
+
+ /* Check that buf is unchanged according to C99 and C11 */
+ tt_str_op(buf, ==, "GH");
done:
if (test_stream != NULL)
@@ -2538,6 +2602,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
+
/** Helper function for testing tor_spawn_background */
static void
run_util_spawn_background(const char *argv[], const char *expected_out,
@@ -2557,19 +2634,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 */
@@ -2580,12 +2666,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);
@@ -2594,6 +2687,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 +2698,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);
}
/** Check that failing to find the executable works as expected */
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 +2732,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;
@@ -2662,22 +2748,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;
+ }
/* Start the program */
#ifdef _WIN32
@@ -2713,6 +2799,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,
@@ -2750,6 +2842,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 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);
+}
+
+#undef TEST_CHILD
+#undef EOL
+
/**
* Test for format_hex_number_sigsafe()
*/
@@ -3685,16 +3846,19 @@ struct testcase_t util_tests[] = {
UTIL_TEST(asprintf, 0),
UTIL_TEST(listdir, 0),
UTIL_TEST(parent_dir, 0),
+ UTIL_TEST(ftruncate, 0),
#ifdef _WIN32
UTIL_TEST(load_win_lib, 0),
#endif
#ifndef _WIN32
UTIL_TEST(exit_status, 0),
- UTIL_TEST(fgets_eagain, TT_SKIP),
+ UTIL_TEST(fgets_eagain, 0),
#endif
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),