Skip to content

tests: port the test harness to Windows #440

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

if(CMAKE_SYSTEM_NAME STREQUAL Windows)
execute_process(COMMAND
"${CMAKE_COMMAND}" -E copy "${PROJECT_SOURCE_DIR}/private"
"${CMAKE_COMMAND}" -E copy_directory "${PROJECT_SOURCE_DIR}/private"
"${CMAKE_CURRENT_BINARY_DIR}/dispatch")
execute_process(COMMAND
"${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/leaks-wrapper.sh"
Expand Down Expand Up @@ -36,6 +36,15 @@ if(BSD_OVERLAY_FOUND)
PRIVATE
${BSD_OVERLAY_CFLAGS})
endif()
if (WIN32)
target_sources(bsdtests
PRIVATE
generic_win_port.c)
target_compile_definitions(bsdtests
PUBLIC
_CRT_NONSTDC_NO_WARNINGS
_CRT_SECURE_NO_WARNINGS)
endif ()

add_executable(bsdtestharness
bsdtestharness.c)
Expand Down Expand Up @@ -91,11 +100,11 @@ function(add_unit_test name)
endif()
if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC")
target_compile_options(${name} PRIVATE -Xclang -fblocks)
target_compile_options(${name} PRIVATE /W3 -Wno-deprecated-declarations)
else()
target_compile_options(${name} PRIVATE -fblocks)
target_compile_options(${name} PRIVATE -Wall -Wno-deprecated-declarations)
endif()
# TODO(compnerd) make this portable
target_compile_options(${name} PRIVATE -Wall -Wno-deprecated-declarations)
dispatch_set_linker(${name})
target_link_libraries(${name}
PRIVATE
Expand Down Expand Up @@ -187,4 +196,4 @@ target_link_libraries(dispatch_group PRIVATE m)
target_link_libraries(dispatch_timer_short PRIVATE m)

# test-specific compile options
target_compile_options(dispatch_c99 PRIVATE -std=c99)
set_target_properties(dispatch_c99 PROPERTIES C_STANDARD 99)
88 changes: 71 additions & 17 deletions tests/bsdtestharness.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,29 @@

#include <dispatch/dispatch.h>
#include <assert.h>
#include <spawn.h>
#include <stdio.h>
#include <stdlib.h>
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#include <spawn.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <unistd.h>
#elif defined(_WIN32)
#include <generic_win_port.h>
#include <Psapi.h>
#include <Windows.h>
#endif
#include <signal.h>
#ifdef __APPLE__
#include <mach/clock_types.h>
#include <mach-o/arch.h>
#endif
#include <sys/resource.h>
#include <sys/time.h>
#if defined(__linux__) || defined(__FreeBSD__)
#include <sys/wait.h>
#endif

#include <bsdtests.h>

#if !defined(_WIN32)
extern char **environ;

#ifdef __linux__
// Linux lacks the DISPATCH_SOURCE_TYPE_PROC functionality
// the real test harness needs.
#define SIMPLE_TEST_HARNESS 1
#else
#define SIMPLE_TEST_HARNESS 0
#endif

int
Expand Down Expand Up @@ -131,25 +127,43 @@ main(int argc, char *argv[])
_Exit(EXIT_FAILURE);
}
}
#elif defined(_WIN32)
(void)res;
WCHAR *cmdline = argv_to_command_line(newargv);
if (!cmdline) {
fprintf(stderr, "argv_to_command_line() failed\n");
exit(EXIT_FAILURE);
}
STARTUPINFOW si = {.cb = sizeof(si)};
PROCESS_INFORMATION pi;
BOOL created = CreateProcessW(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
DWORD error = GetLastError();
free(cmdline);
if (!created) {
print_winapi_error("CreateProcessW", error);
exit(EXIT_FAILURE);
}
pid = (pid_t)pi.dwProcessId;
#else
#error "bsdtestharness not implemented on this platform"
#endif

//fprintf(stderr, "pid = %d\n", pid);
assert(pid > 0);

#if SIMPLE_TEST_HARNESS
#if defined(__linux__)
int status;
struct rusage usage;
struct timeval tv_stop, tv_wall;

int res2 = wait4(pid, &status, 0, &usage);
(void)res2;

gettimeofday(&tv_stop, NULL);
tv_wall.tv_sec = tv_stop.tv_sec - tv_start.tv_sec;
tv_wall.tv_sec -= (tv_stop.tv_usec < tv_start.tv_usec);
tv_wall.tv_usec = labs(tv_stop.tv_usec - tv_start.tv_usec);

int res2 = wait4(pid, &status, 0, &usage);
(void)res2;
assert(res2 != -1);
test_long("Process exited", (WIFEXITED(status) && WEXITSTATUS(status) && WEXITSTATUS(status) != 0xff) || WIFSIGNALED(status), 0);
printf("[PERF]\twall time: %ld.%06ld\n", tv_wall.tv_sec, tv_wall.tv_usec);
Expand All @@ -161,6 +175,46 @@ main(int argc, char *argv[])
printf("[PERF]\tvoluntary context switches: %ld\n", usage.ru_nvcsw);
printf("[PERF]\tinvoluntary context switches: %ld\n", usage.ru_nivcsw);
exit((WIFEXITED(status) && WEXITSTATUS(status)) || WIFSIGNALED(status));
#elif defined(_WIN32)
if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_OBJECT_0) {
print_winapi_error("WaitForSingleObject", GetLastError());
exit(EXIT_FAILURE);
}

struct timeval tv_stop, tv_wall;
gettimeofday(&tv_stop, NULL);
tv_wall.tv_sec = tv_stop.tv_sec - tv_start.tv_sec;
tv_wall.tv_sec -= (tv_stop.tv_usec < tv_start.tv_usec);
tv_wall.tv_usec = labs(tv_stop.tv_usec - tv_start.tv_usec);

DWORD status;
if (!GetExitCodeProcess(pi.hProcess, &status)) {
print_winapi_error("GetExitCodeProcess", GetLastError());
exit(EXIT_FAILURE);
}

FILETIME create_time, exit_time, kernel_time, user_time;
if (!GetProcessTimes(pi.hProcess, &create_time, &exit_time, &kernel_time, &user_time)) {
print_winapi_error("GetProcessTimes", GetLastError());
exit(EXIT_FAILURE);
}
struct timeval utime, stime;
filetime_to_timeval(&utime, &user_time);
filetime_to_timeval(&stime, &kernel_time);

PROCESS_MEMORY_COUNTERS counters;
if (!GetProcessMemoryInfo(pi.hProcess, &counters, sizeof(counters))) {
print_winapi_error("GetProcessMemoryInfo", GetLastError());
exit(EXIT_FAILURE);
}

test_long("Process exited", status == 0 || status == 0xff, 1);
printf("[PERF]\twall time: %ld.%06ld\n", tv_wall.tv_sec, tv_wall.tv_usec);
printf("[PERF]\tuser time: %ld.%06ld\n", utime.tv_sec, utime.tv_usec);
printf("[PERF]\tsystem time: %ld.%06ld\n", stime.tv_sec, stime.tv_usec);
printf("[PERF]\tmax working set size: %zu\n", counters.PeakWorkingSetSize);
printf("[PERF]\tpage faults: %lu\n", counters.PageFaultCount);
exit(status ? EXIT_FAILURE : EXIT_SUCCESS);
#else
dispatch_queue_t main_q = dispatch_get_main_queue();

Expand Down Expand Up @@ -219,7 +273,7 @@ main(int argc, char *argv[])
kill(pid, SIGCONT);

dispatch_main();
#endif // SIMPLE_TEST_HARNESS
#endif

return 0;
}
22 changes: 10 additions & 12 deletions tests/bsdtests.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@
#include <unistd.h>
#endif
#include <errno.h>
#include <sys/errno.h>
#include <sys/wait.h>
#include <string.h>
#ifdef __APPLE__
#include <crt_externs.h>
#include <mach/mach_error.h>
#endif
#include <spawn.h>
#include <sys/wait.h>
#endif
#if defined(_WIN32)
#include <generic_win_port.h>
#endif
#include <inttypes.h>
#include "bsdtests.h"

Expand Down Expand Up @@ -454,18 +456,11 @@ test_start(const char* desc)
usleep(100000); // give 'gdb --waitfor=' a chance to find this proc
}

#if defined(__linux__) || defined(__FreeBSD__)
static char** get_environment(void)
{
extern char **environ;
return environ;
}
#else
#if defined(__APPLE__) && defined(__MACH__)
static char** get_environment(void)
{
return (* _NSGetEnviron());
}
#endif

void
test_leaks_pid(const char *name, pid_t pid)
Expand Down Expand Up @@ -517,15 +512,18 @@ test_leaks(const char *name)
{
test_leaks_pid(name, getpid());
}
#endif

void
test_stop_after_delay(void *delay)
{
if (delay != NULL) {
sleep((uint)(intptr_t)delay);
sleep((unsigned int)(intptr_t)delay);
}

#if defined(__APPLE__) && defined(__MACH__)
test_leaks(NULL);
#endif

fflush(stdout);
_exit(_test_exit_code);
Expand Down
10 changes: 8 additions & 2 deletions tests/bsdtests.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,22 @@ __BASENAME__(const char *_str_)
}
#define __SOURCE_FILE__ __BASENAME__(__FILE__)

__BEGIN_DECLS
#if defined(__cplusplus)
extern "C" {
#endif

/**
* test_start() provides the TEST token. Use this once per test "tool"
*/
void test_start(const char* desc);

#if defined(__APPLE__) && defined(__MACH__)
/**
* Explicitly runs the 'leaks' test without stopping the process.
*/
void test_leaks_pid(const char *name, pid_t pid);
void test_leaks(const char *name);
#endif

/**
* test_stop() checks for leaks during the tests using leaks-wrapper. Use this at the end of each "tool"
Expand Down Expand Up @@ -179,6 +183,8 @@ void _test_skip(const char* file, long line, const char* desc);
#define test_skip2(m) _test_skip("", 0, m)
void test_skip_format(const char *format, ...) __printflike(1,2);

__END_DECLS
#if defined(__cplusplus)
} /* extern "C" */
#endif

#endif /* __BSD_TEST_H__ */
25 changes: 24 additions & 1 deletion tests/dispatch_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@
#include <stdio.h>
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#include <unistd.h>
#endif
#if __has_include(<sys/event.h>)
#define HAS_SYS_EVENT_H 1
#include <sys/event.h>
#else
#include <sys/poll.h>
#endif
#elif defined(_WIN32)
#include <io.h>
#include <Windows.h>
#endif
#include <assert.h>

#include <dispatch/dispatch.h>
Expand Down Expand Up @@ -68,6 +71,20 @@ dispatch_test_check_evfilt_read_for_fd(int fd)
int r = kevent(kq, &ke, 1, &ke, 1, &t);
close(kq);
return r > 0;
#elif defined(_WIN32)
HANDLE handle = (HANDLE)_get_osfhandle(fd);
// A zero-distance move retrieves the file pointer
LARGE_INTEGER currentPosition;
LARGE_INTEGER distance = {.QuadPart = 0};
if (!SetFilePointerEx(handle, distance, &currentPosition, FILE_CURRENT)) {
return false;
}
// If we are not at the end, assume the file is readable
LARGE_INTEGER fileSize;
if (GetFileSizeEx(handle, &fileSize) == 0) {
return false;
}
return currentPosition.QuadPart < fileSize.QuadPart;
#else
struct pollfd pfd = {
.fd = fd,
Expand Down Expand Up @@ -141,6 +158,10 @@ dispatch_test_get_large_file(void)
close(temp_fd);
free(file_buf);
return path;
#elif defined(_WIN32)
// TODO
fprintf(stderr, "dispatch_test_get_large_file() not implemented on Windows\n");
abort();
#else
#error "dispatch_test_get_large_file not implemented on this platform"
#endif
Expand All @@ -154,6 +175,8 @@ dispatch_test_release_large_file(const char *path)
(void)path;
#elif defined(__unix__)
unlink(path);
#elif defined(_WIN32)
// TODO
#else
#error "dispatch_test_release_large_file not implemented on this platform"
#endif
Expand Down
11 changes: 8 additions & 3 deletions tests/dispatch_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@
* @APPLE_APACHE_LICENSE_HEADER_END@
*/

#include <sys/cdefs.h>
#include <stdbool.h>
#include <dispatch/dispatch.h>

#if defined(__linux__) || defined(__FreeBSD__)
#include <generic_unix_port.h>
#elif defined(_WIN32)
#include <generic_win_port.h>
#endif

#define test_group_wait(g) do { \
Expand All @@ -33,7 +34,9 @@
test_stop(); \
} } while (0)

__BEGIN_DECLS
#if defined(__cplusplus)
extern "C" {
#endif

void dispatch_test_start(const char* desc);

Expand All @@ -50,4 +53,6 @@ int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
size_t *newpl);
#endif

__END_DECLS
#if defined(__cplusplus)
} /* extern "C" */
#endif
Loading