diff options
author | Frediano Ziglio <fziglio@redhat.com> | 2016-10-08 19:25:00 +0100 |
---|---|---|
committer | Frediano Ziglio <fziglio@redhat.com> | 2016-10-08 22:56:04 +0100 |
commit | 3f034f3401d30b40b03a0ac44f923e324847aeba (patch) | |
tree | c618ed00c43fc38791119a7237258bd668914d85 | |
parent | 45eb0d5c014707614710d39287c264e7428ad0dd (diff) |
Add some automatic tests
Add test infrastructure.
Add a "delay" test checking delay introduced is correct.
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | tests/Makefile.am | 17 | ||||
-rw-r--r-- | tests/common.c | 149 | ||||
-rw-r--r-- | tests/common.h | 31 | ||||
-rw-r--r-- | tests/delay.c | 91 |
7 files changed, 297 insertions, 2 deletions
@@ -18,3 +18,7 @@ depcomp missing *.o latency.spec +ar-lib +tests/libtest.a +tests/delay +.*.swp diff --git a/Makefile.am b/Makefile.am index 1bdcb7c..02bd15f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,5 @@ NULL = +SUBDIRS = . tests bin_PROGRAMS = latency latency_SOURCES = \ diff --git a/configure.ac b/configure.ac index 6e017da..8b4c7bc 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,8 @@ AC_INIT([latency], [1.0], [freddy77@gmail.com]) -AM_INIT_AUTOMAKE([-Wall -Werror foreign]) +AM_INIT_AUTOMAKE([serial-tests -Wall -Werror foreign]) AC_PROG_CC +AM_PROG_AR +AC_PROG_RANLIB AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_FILES([Makefile latency.spec]) +AC_CONFIG_FILES([Makefile tests/Makefile latency.spec]) AC_OUTPUT diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 0000000..b3c9f45 --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,17 @@ +NULL = + +TESTS = +noinst_PROGRAMS = $(TESTS) +check_PROGRAMS = $(TESTS) + +# common code +noinst_LIBRARIES = libtest.a +libtest_a_SOURCES = \ + common.c \ + $(NULL) +LDADD = \ + libtest.a \ + $(NULL) + +TESTS += delay +delay_SOURCES = delay.c diff --git a/tests/common.c b/tests/common.c new file mode 100644 index 0000000..58e86b8 --- /dev/null +++ b/tests/common.c @@ -0,0 +1,149 @@ +#include "common.h" +#include <stdarg.h> +#include <errno.h> +#include <signal.h> +#include <sys/wait.h> +#include <arpa/inet.h> + +static pid_t latency_pid = -1; + +bool +latency_running(void) +{ + int socktrue = 1; + sockaddr_all addr; + + int sock = socket(AF_INET, SOCK_DGRAM, 0); + assert(sock >= 0); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &socktrue, sizeof(socktrue)); + setup_addr(&addr, "192.168.127.0", 0); + bool res; + if (bind(sock, &addr.generic, sizeof(addr)) == 0) { + res = true; + } else { + assert(errno == EADDRNOTAVAIL); + res = false; + } + close(sock); + return res; +} + +void +launch_latency(const char *fmt, ...) +{ + assert(latency_pid == -1); + + while (latency_running()) { + system("killall latency > /dev/null 2> /dev/null"); + usleep(2000); + } + + char cmd[1024]; + va_list ap; + + strcpy(cmd, "exec ../latency "); + size_t cmd_len = strlen(cmd); + + va_start(ap, fmt); + vsnprintf(cmd + cmd_len, sizeof(cmd) - cmd_len, fmt, ap); + va_end(ap); + + printf("starting %s\n", cmd); + latency_pid = fork(); + assert(latency_pid != -1); + + if (latency_pid == 0) { + execlp("sh", "sh", "-c", cmd, NULL); + kill(getpid(), SIGKILL); + exit(1); + } + + int count; + while (!latency_running()) { + usleep(2000); + assert(++count < 100); + } + usleep(50000); +} + +static void +handle_alarm(int sig) +{ +} + +void +kill_latency(void) +{ + assert(latency_pid != -1); + kill(latency_pid, SIGTERM); + + // handle some timeout + signal(SIGALRM, handle_alarm); + alarm(1); + + int status; + pid_t pid = waitpid(latency_pid, &status, 0); + alarm(0); + signal(SIGALRM, SIG_DFL); + + assert(pid == latency_pid); + assert(WIFEXITED(status)); + assert(WEXITSTATUS(status) == 0); + + latency_pid = -1; +} + +void +setup_addr(sockaddr_all *addr, const char *ip, int port) +{ + struct in_addr inet; + assert(inet_aton(ip, &inet) == 1); + + addr->inet.sin_family = AF_INET; + addr->inet.sin_addr = inet; + addr->inet.sin_port = htons(port); +} + +void +create_udp_pair(int socks[2]) +{ + int sock; + int socktrue = 1; + sockaddr_all addr; + socklen_t addr_len; + int ports[2]; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + assert(sock >= 0); + socks[0] = sock; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &socktrue, sizeof(socktrue)); + setup_addr(&addr, "192.168.127.0", 0); + assert(bind(sock, &addr.generic, sizeof(addr)) == 0); + addr_len = sizeof(addr); + assert(getsockname(sock, &addr.generic, &addr_len) == 0); + ports[0] = ntohs(addr.inet.sin_port); + + sock = socket(AF_INET, SOCK_DGRAM, 0); + assert(sock >= 0); + socks[1] = sock; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &socktrue, sizeof(socktrue)); + setup_addr(&addr, "192.168.127.0", 0); + assert(bind(sock, &addr.generic, sizeof(addr)) == 0); + addr_len = sizeof(addr); + assert(getsockname(sock, &addr.generic, &addr_len) == 0); + ports[1] = ntohs(addr.inet.sin_port); + + // make a pair from the above ones + setup_addr(&addr, "192.168.127.1", ports[1]); + assert(connect(socks[0], &addr.generic, sizeof(addr)) == 0); + setup_addr(&addr, "192.168.127.1", ports[0]); + assert(connect(socks[1], &addr.generic, sizeof(addr)) == 0); +} + +void +close_udp_pair(int socks[2]) +{ + close(socks[0]); + close(socks[1]); + socks[0] = socks[1] = -1; +} diff --git a/tests/common.h b/tests/common.h new file mode 100644 index 0000000..9c72998 --- /dev/null +++ b/tests/common.h @@ -0,0 +1,31 @@ +#undef NDEBUG +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <stdint.h> +#include <assert.h> +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> + +/** check if latency executable is running */ +bool latency_running(void); + +/** launch a program with given parameters */ +void launch_latency(const char *fmt, ...); + +/** kill latency process */ +void kill_latency(void); + +typedef union { + struct sockaddr generic; + struct sockaddr_in inet; + struct sockaddr_in6 inet6; +} sockaddr_all; + +void setup_addr(sockaddr_all *addr, const char *ip, int port); + +/** open a UDP pair that uses latency program */ +void create_udp_pair(int socks[2]); +void close_udp_pair(int socks[2]); diff --git a/tests/delay.c b/tests/delay.c new file mode 100644 index 0000000..aea5512 --- /dev/null +++ b/tests/delay.c @@ -0,0 +1,91 @@ +/* check that the delay we setup is respected */ +#include "common.h" +#include "../utils.h" +#include <poll.h> + +static unsigned test_num = 0; +static int udp_socks[2] = { -1, -1 }; +static const char payload_id[8] = "DELAY\0\0"; + +typedef struct { + char id[8]; + unsigned test_num; + uint64_t time; +} test_payload; + +static void +wait_reply(int sock, test_payload *payload) +{ + struct pollfd fds[1]; + for (;;) { + // wait a packet or bail out on timeout + fds[0].fd = sock; + fds[0].events = POLLIN; + fds[0].revents = 0; + int res = poll(fds, 1, 1000); + assert(res == 1); + + // check packet received is what we expect + if (recv(sock, payload, sizeof(*payload), MSG_TRUNC) != sizeof(*payload)) + continue; + if (memcmp(payload->id, payload_id, sizeof(payload->id)) != 0) + continue; + if (payload->test_num != test_num) + continue; + + // got it! + return; + } +} + +static void +test_latency(unsigned latency) +{ + ++test_num; + // launch program with given latency + launch_latency("%u 100M", latency); + create_udp_pair(udp_socks); + + // send some payload and wait + int i; + unsigned count = 0, total_delay = 0; + for (i = 0; i < 4; ++i) { + uint64_t time = get_time_us(); + test_payload payload; + memcpy(payload.id, payload_id, sizeof(payload.id)); + payload.test_num = test_num; + payload.time = time + latency * 1000; + + send(udp_socks[i&1], &payload, sizeof(payload), MSG_NOSIGNAL); + + wait_reply(udp_socks[1 - (i&1)], &payload); + + // check the time is more or less what we expect + time = get_time_us(); + assert(time > payload.time); + if (time - payload.time > 4000) { + fprintf(stderr, "Expected time %" PRIu64 " current %" PRIu64 " elapsed %" PRIu64"\n", + payload.time, time, time - payload.time); + exit(1); + } + ++count; + total_delay += (unsigned) (time - payload.time); + } + if (total_delay / count > 1500) { + fprintf(stderr, "Average delay %u > 1500\n", total_delay / count); + exit(1); + } + close_udp_pair(udp_socks); + kill_latency(); +} + +int main(void) +{ + printf("Testing delay introduced is correct\n"); + + test_latency(10); + test_latency(100); + test_latency(200); + test_latency(280); + return 0; +} |