test-runner compiles
This commit is contained in:
parent
01cd1c5b17
commit
769948a5ad
3
.gitignore
vendored
3
.gitignore
vendored
@ -22,5 +22,4 @@ ev/autom4te.cache
|
||||
/Win32/
|
||||
/x64/
|
||||
|
||||
test/echo-demo
|
||||
test/test-ping-pong
|
||||
test/test-runner
|
||||
|
||||
13
Makefile
13
Makefile
@ -1,4 +1,13 @@
|
||||
all: oio.a
|
||||
all: oio.a test/test-runner
|
||||
|
||||
TESTS=test/echo-server.c \
|
||||
test/test-pass-always.c \
|
||||
test/test-fail-always.c \
|
||||
test/test-ping-pong.c \
|
||||
test/test-callback-stack.c
|
||||
|
||||
test/test-runner: test/*.h test/test-runner.c test/test-runner-unix.c $(TESTS) oio.a
|
||||
$(CC) -ansi -g -lm -o test/test-runner test/test-runner.c test/test-runner-unix.c $(TESTS) oio.a
|
||||
|
||||
test/echo-demo: test/echo-demo.c test/echo.o oio.a
|
||||
$(CC) -ansi -g -o test/echo-demo test/echo-demo.c test/echo.o oio.a -lm
|
||||
@ -25,7 +34,7 @@ ev/config.h:
|
||||
.PHONY: clean distclean
|
||||
|
||||
clean:
|
||||
$(RM) -f *.o *.a
|
||||
$(RM) -f *.o *.a test/test-runner
|
||||
$(MAKE) -C ev clean
|
||||
|
||||
distclean:
|
||||
|
||||
11
oio-unix.c
11
oio-unix.c
@ -67,6 +67,11 @@ int oio_run() {
|
||||
}
|
||||
|
||||
|
||||
int oio_tcp_handle_init(oio_handle *handle, oio_close_cb close_cb, void* data) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Remove me */
|
||||
oio_handle* oio_tcp_handle_new(oio_close_cb close_cb, void* data) {
|
||||
oio_handle *handle = calloc(sizeof(oio_handle), 1);
|
||||
if (!handle) {
|
||||
@ -207,6 +212,12 @@ int oio_listen(oio_handle* handle, int backlog, oio_accept_cb cb) {
|
||||
}
|
||||
|
||||
|
||||
int oio_tcp_handle_accept(oio_handle* server, oio_handle* client,
|
||||
oio_close_cb close_cb, void* data) {
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
int oio_close_error(oio_handle* handle, oio_err err) {
|
||||
ev_io_stop(EV_DEFAULT_ &handle->read_watcher);
|
||||
close(handle->fd);
|
||||
|
||||
@ -126,4 +126,4 @@ TEST_IMPL(echo_server) {
|
||||
fprintf(stderr, "Listening!\n");
|
||||
oio_run();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,4 +13,4 @@ TEST_LIST_START
|
||||
TEST_ENTRY (fail_always)
|
||||
|
||||
TEST_ENTRY (pass_always)
|
||||
TEST_LIST_END
|
||||
TEST_LIST_END
|
||||
|
||||
157
test/test-runner-unix.c
Normal file
157
test/test-runner-unix.c
Normal file
@ -0,0 +1,157 @@
|
||||
#include "test-runner-unix.h"
|
||||
#include "test-runner.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
|
||||
#define PATHMAX 1024
|
||||
static char executable_path[PATHMAX] = { '\0' };
|
||||
|
||||
|
||||
/* Linux-only */
|
||||
static void get_executable_path() {
|
||||
if (!executable_path[0]) {
|
||||
readlink("/proc/self/exe", executable_path, PATHMAX - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Invoke "arv[0] test-name". Store process info in *p. */
|
||||
/* Make sure that all stdio output of the processes is buffered up. */
|
||||
int process_start(char* name, process_info_t* p) {
|
||||
FILE* stdout_file = tmpfile();
|
||||
if (!stdout_file) {
|
||||
perror("tmpfile");
|
||||
return -1;
|
||||
}
|
||||
|
||||
p->terminated = 0;
|
||||
|
||||
get_executable_path();
|
||||
|
||||
pid_t pid = vfork();
|
||||
|
||||
if (pid < 0) {
|
||||
perror("vfork");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
dup2(fileno(stdout_file), STDOUT_FILENO);
|
||||
dup2(fileno(stdout_file), STDERR_FILENO);
|
||||
|
||||
char* args[3] = { executable_path, name, NULL };
|
||||
execvp(executable_path, args);
|
||||
perror("execvp()");
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
/* parent */
|
||||
p->pid = pid;
|
||||
p->name = strdup(name);
|
||||
p->stdout_file = stdout_file;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Wait for all `n` processes in `vec` to terminate. */
|
||||
/* Time out after `timeout` msec, or never if timeout == -1 */
|
||||
/* Return 0 if all processes are terminated, -1 on error, -2 on timeout. */
|
||||
int process_wait(process_info_t* vec, int n, int timeout) {
|
||||
int i;
|
||||
process_info_t* p;
|
||||
for (i = 0; i < n; i++) {
|
||||
p = (process_info_t*)(vec + i * sizeof(process_info_t));
|
||||
if (p->terminated) continue;
|
||||
int status = 0;
|
||||
int r = waitpid(p->pid, &p->status, 0);
|
||||
if (r < 0) {
|
||||
return -1;
|
||||
}
|
||||
p->terminated = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Returns the number of bytes in the stdio output buffer for process `p`. */
|
||||
long int process_output_size(process_info_t *p) {
|
||||
/* Size of the p->stdout_file */
|
||||
struct stat buf;
|
||||
|
||||
int r = fstat(fileno(p->stdout_file), &buf);
|
||||
if (r < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (long)buf.st_size;
|
||||
}
|
||||
|
||||
|
||||
/* Copy the contents of the stdio output buffer to `fd`. */
|
||||
int process_copy_output(process_info_t *p, int fd) {
|
||||
int r = fseek(p->stdout_file, 0, SEEK_SET);
|
||||
if (r < 0) {
|
||||
perror("fseek");
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t nread, nwritten;
|
||||
char buf[1024];
|
||||
|
||||
while ((nread = read(fileno(p->stdout_file), buf, 1024)) > 0) {
|
||||
nwritten = write(fd, buf, nread);
|
||||
/* TODO: what if write doesn't write the whole buffer... */
|
||||
if (nwritten < 0) {
|
||||
perror("write");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (nread < 0) {
|
||||
perror("read");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return the name that was specified when `p` was started by process_start */
|
||||
char* process_get_name(process_info_t *p) {
|
||||
return p->name;
|
||||
}
|
||||
|
||||
|
||||
/* Terminate process `p`. */
|
||||
int process_terminate(process_info_t *p) {
|
||||
return kill(p->pid, SIGTERM);
|
||||
}
|
||||
|
||||
|
||||
/* Return the exit code of process p. */
|
||||
/* On error, return -1. */
|
||||
int process_reap(process_info_t *p) {
|
||||
return WEXITSTATUS(p->status);
|
||||
}
|
||||
|
||||
|
||||
/* Clean up after terminating process `p` (e.g. free the output buffer etc.). */
|
||||
void process_cleanup(process_info_t *p) {
|
||||
fclose(p->stdout_file);
|
||||
free(p->name);
|
||||
}
|
||||
|
||||
|
||||
/* Move the console cursor one line up and back to the first column. */
|
||||
int rewind_cursor() {
|
||||
printf("\033[1A\033[80D");
|
||||
}
|
||||
15
test/test-runner-unix.h
Normal file
15
test/test-runner-unix.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef TEST_RUNNER_UNIX_H
|
||||
#define TEST_RUNNER_UNIX_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h> /* FILE */
|
||||
|
||||
typedef struct {
|
||||
FILE* stdout_file;
|
||||
pid_t pid;
|
||||
char* name;
|
||||
int status;
|
||||
int terminated;
|
||||
} process_info_t;
|
||||
|
||||
#endif /* TEST_RUNNER_UNIX_H */
|
||||
@ -2,7 +2,7 @@
|
||||
#include "test-runner.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -176,4 +176,4 @@ int main(int argc, char **argv) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,4 +80,4 @@ void process_cleanup(process_info_t *p);
|
||||
/* Move the console cursor one line up and back to the first column. */
|
||||
int rewind_cursor();
|
||||
|
||||
#endif /* TEST_RUNNER_H_ */
|
||||
#endif /* TEST_RUNNER_H_ */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user