mirror of
https://github.com/cuberite/libevent.git
synced 2025-08-04 01:36:23 -04:00
tinytest: support timeout on Windows
(cherry picked from commit 8d5c5650d281019832fa7b5133b85c7ad29f664e)
This commit is contained in:
parent
a4f0387c22
commit
794e8f75b5
109
test/tinytest.c
109
test/tinytest.c
@ -60,12 +60,8 @@
|
|||||||
#include "tinytest_macros.h"
|
#include "tinytest_macros.h"
|
||||||
|
|
||||||
#define LONGEST_TEST_NAME 16384
|
#define LONGEST_TEST_NAME 16384
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#define DEFAULT_TESTCASE_TIMEOUT 30U
|
#define DEFAULT_TESTCASE_TIMEOUT 30U
|
||||||
#else
|
#define MAGIC_EXITCODE 42
|
||||||
#define DEFAULT_TESTCASE_TIMEOUT 0U
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
|
static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
|
||||||
static int n_ok = 0; /**< Number of tests that have passed */
|
static int n_ok = 0; /**< Number of tests that have passed */
|
||||||
@ -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 */
|
/** Name of the current test, if we haven't logged is yet. Used for --quiet */
|
||||||
const char *cur_test_name = NULL;
|
const char *cur_test_name = NULL;
|
||||||
|
|
||||||
#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)
|
static void usage(struct testgroup_t *groups, int list_groups)
|
||||||
__attribute__((noreturn));
|
__attribute__((noreturn));
|
||||||
static int process_test_option(struct testgroup_t *groups, const char *test);
|
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];
|
||||||
|
|
||||||
|
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)
|
static unsigned int testcase_set_timeout_(void)
|
||||||
{
|
{
|
||||||
if (!opt_timeout)
|
|
||||||
return 0;
|
|
||||||
#ifndef _WIN32
|
|
||||||
return alarm(opt_timeout);
|
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)
|
static unsigned int testcase_reset_timeout_(void)
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
|
||||||
return alarm(0);
|
return alarm(0);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static enum outcome
|
static enum outcome
|
||||||
testcase_run_bare_(const struct testcase_t *testcase)
|
testcase_run_bare_(const struct testcase_t *testcase)
|
||||||
@ -129,9 +165,17 @@ testcase_run_bare_(const struct testcase_t *testcase)
|
|||||||
|
|
||||||
cur_test_outcome = OK;
|
cur_test_outcome = OK;
|
||||||
{
|
{
|
||||||
|
if (opt_timeout) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
cur_test_outcome = testcase_run_in_thread_(testcase, env);
|
||||||
|
#else
|
||||||
testcase_set_timeout_();
|
testcase_set_timeout_();
|
||||||
testcase->fn(env);
|
testcase->fn(env);
|
||||||
testcase_reset_timeout_();
|
testcase_reset_timeout_();
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
testcase->fn(env);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
outcome = cur_test_outcome;
|
outcome = cur_test_outcome;
|
||||||
|
|
||||||
@ -143,7 +187,6 @@ testcase_run_bare_(const struct testcase_t *testcase)
|
|||||||
return outcome;
|
return outcome;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAGIC_EXITCODE 42
|
|
||||||
|
|
||||||
#ifndef NO_FORKING
|
#ifndef NO_FORKING
|
||||||
|
|
||||||
@ -164,7 +207,7 @@ testcase_run_forked_(const struct testgroup_t *group,
|
|||||||
char buffer[LONGEST_TEST_NAME+256];
|
char buffer[LONGEST_TEST_NAME+256];
|
||||||
STARTUPINFOA si;
|
STARTUPINFOA si;
|
||||||
PROCESS_INFORMATION info;
|
PROCESS_INFORMATION info;
|
||||||
DWORD exitcode;
|
DWORD ret;
|
||||||
|
|
||||||
if (!in_tinytest_main) {
|
if (!in_tinytest_main) {
|
||||||
printf("\nERROR. On Windows, testcase_run_forked_ must be"
|
printf("\nERROR. On Windows, testcase_run_forked_ must be"
|
||||||
@ -174,7 +217,7 @@ testcase_run_forked_(const struct testgroup_t *group,
|
|||||||
if (opt_verbosity>0)
|
if (opt_verbosity>0)
|
||||||
printf("[forking] ");
|
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);
|
commandname, verbosity_flag, group->prefix, testcase->name);
|
||||||
|
|
||||||
memset(&si, 0, sizeof(si));
|
memset(&si, 0, sizeof(si));
|
||||||
@ -185,15 +228,23 @@ testcase_run_forked_(const struct testgroup_t *group,
|
|||||||
0, NULL, NULL, &si, &info);
|
0, NULL, NULL, &si, &info);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
printf("CreateProcess failed!\n");
|
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.hProcess);
|
||||||
CloseHandle(info.hThread);
|
CloseHandle(info.hThread);
|
||||||
if (exitcode == 0)
|
if (ret == 0)
|
||||||
return OK;
|
return OK;
|
||||||
else if (exitcode == MAGIC_EXITCODE)
|
else if (ret == MAGIC_EXITCODE)
|
||||||
return SKIP;
|
return SKIP;
|
||||||
else
|
else
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@ -520,7 +571,7 @@ tinytest_set_test_failed_(void)
|
|||||||
printf("%s%s: ", cur_test_prefix, cur_test_name);
|
printf("%s%s: ", cur_test_prefix, cur_test_name);
|
||||||
cur_test_name = NULL;
|
cur_test_name = NULL;
|
||||||
}
|
}
|
||||||
cur_test_outcome = 0;
|
cur_test_outcome = FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
Loading…
x
Reference in New Issue
Block a user