Skip to content

Commit

Permalink
tinytest: support timeout on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
yuangongji committed Sep 26, 2019
1 parent a977d69 commit 8d5c565
Showing 1 changed file with 82 additions and 31 deletions.
113 changes: 82 additions & 31 deletions test/tinytest.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,8 @@
#include "tinytest_macros.h"

#define LONGEST_TEST_NAME 16384

#ifndef _WIN32
#define DEFAULT_TESTCASE_TIMEOUT 30U
#else
#define DEFAULT_TESTCASE_TIMEOUT 0U
#endif
#define MAGIC_EXITCODE 42

static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
static int n_ok = 0; /**< Number of tests that have passed */
Expand All @@ -86,33 +82,73 @@ const char *cur_test_prefix = NULL; /**< prefix of the current test group */
/** Name of the current test, if we haven't logged is yet. Used for --quiet */
const char *cur_test_name = NULL;

static void usage(struct testgroup_t *groups, int list_groups)
__attribute__((noreturn));
static int process_test_option(struct testgroup_t *groups, const char *test);

#ifdef _WIN32
/* Copy of argv[0] for win32. */
static char commandname[MAX_PATH+1];
#endif

static void usage(struct testgroup_t *groups, int list_groups)
__attribute__((noreturn));
static int process_test_option(struct testgroup_t *groups, const char *test);
struct timeout_thread_args {
const testcase_fn *fn;
void *env;
};

static DWORD WINAPI
timeout_thread_proc_(LPVOID arg)
{
struct timeout_thread_args *args = arg;
(*(args->fn))(args->env);
ExitThread(cur_test_outcome == FAIL ? 1 : 0);
}

static enum outcome
testcase_run_in_thread_(const struct testcase_t *testcase, void *env)
{
/* We will never run testcase in a new thread when the
timeout is set to zero */
assert(opt_timeout);
DWORD ret, tid;
HANDLE handle;
struct timeout_thread_args args = {
&(testcase->fn),
env
};

handle =CreateThread(NULL, 0, timeout_thread_proc_,
(LPVOID)&args, 0, &tid);
ret = WaitForSingleObject(handle, opt_timeout * 1000U);
if (ret == WAIT_OBJECT_0) {
ret = 0;
if (!GetExitCodeThread(handle, &ret)) {
printf("GetExitCodeThread failed\n");
ret = 1;
}
} else if (ret == WAIT_TIMEOUT) {
printf("timeout\n");
} else {
printf("Wait failed\n");
}
CloseHandle(handle);
if (ret == 0)
return OK;
else if (ret == MAGIC_EXITCODE)
return SKIP;
else
return FAIL;
}
#else
static unsigned int testcase_set_timeout_(void)
{
if (!opt_timeout)
return 0;
#ifndef _WIN32
return alarm(opt_timeout);
#else
/** TODO: win32 support */
fprintf(stderr, "You cannot set alarm on windows\n");
exit(1);
#endif
}

static unsigned int testcase_reset_timeout_(void)
{
#ifndef _WIN32
return alarm(0);
#endif
}
#endif

static enum outcome
testcase_run_bare_(const struct testcase_t *testcase)
Expand All @@ -129,9 +165,17 @@ testcase_run_bare_(const struct testcase_t *testcase)

cur_test_outcome = OK;
{
testcase_set_timeout_();
testcase->fn(env);
testcase_reset_timeout_();
if (opt_timeout) {
#ifdef _WIN32
cur_test_outcome = testcase_run_in_thread_(testcase, env);
#else
testcase_set_timeout_();
testcase->fn(env);
testcase_reset_timeout_();
#endif
} else {
testcase->fn(env);
}
}
outcome = cur_test_outcome;

Expand All @@ -143,7 +187,6 @@ testcase_run_bare_(const struct testcase_t *testcase)
return outcome;
}

#define MAGIC_EXITCODE 42

#ifndef NO_FORKING

Expand All @@ -164,7 +207,7 @@ testcase_run_forked_(const struct testgroup_t *group,
char buffer[LONGEST_TEST_NAME+256];
STARTUPINFOA si;
PROCESS_INFORMATION info;
DWORD exitcode;
DWORD ret;

if (!in_tinytest_main) {
printf("\nERROR. On Windows, testcase_run_forked_ must be"
Expand All @@ -174,7 +217,7 @@ testcase_run_forked_(const struct testgroup_t *group,
if (opt_verbosity>0)
printf("[forking] ");

snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s",
snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s --timeout 0 %s%s",
commandname, verbosity_flag, group->prefix, testcase->name);

memset(&si, 0, sizeof(si));
Expand All @@ -185,15 +228,23 @@ testcase_run_forked_(const struct testgroup_t *group,
0, NULL, NULL, &si, &info);
if (!ok) {
printf("CreateProcess failed!\n");
return 0;
return FAIL;
}
ret = WaitForSingleObject(info.hProcess,
(opt_timeout ? opt_timeout * 1000U : INFINITE));

if (ret == WAIT_OBJECT_0) {
GetExitCodeProcess(info.hProcess, &ret);
} else if (ret == WAIT_TIMEOUT) {
printf("timeout\n");
} else {
printf("Wait failed\n");
}
WaitForSingleObject(info.hProcess, INFINITE);
GetExitCodeProcess(info.hProcess, &exitcode);
CloseHandle(info.hProcess);
CloseHandle(info.hThread);
if (exitcode == 0)
if (ret == 0)
return OK;
else if (exitcode == MAGIC_EXITCODE)
else if (ret == MAGIC_EXITCODE)
return SKIP;
else
return FAIL;
Expand Down Expand Up @@ -520,7 +571,7 @@ tinytest_set_test_failed_(void)
printf("%s%s: ", cur_test_prefix, cur_test_name);
cur_test_name = NULL;
}
cur_test_outcome = 0;
cur_test_outcome = FAIL;
}

void
Expand Down

0 comments on commit 8d5c565

Please sign in to comment.