summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrediano Ziglio <fziglio@redhat.com>2016-10-08 19:25:00 +0100
committerFrediano Ziglio <fziglio@redhat.com>2016-10-08 22:56:04 +0100
commit3f034f3401d30b40b03a0ac44f923e324847aeba (patch)
treec618ed00c43fc38791119a7237258bd668914d85
parent45eb0d5c014707614710d39287c264e7428ad0dd (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--.gitignore4
-rw-r--r--Makefile.am1
-rw-r--r--configure.ac6
-rw-r--r--tests/Makefile.am17
-rw-r--r--tests/common.c149
-rw-r--r--tests/common.h31
-rw-r--r--tests/delay.c91
7 files changed, 297 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index aeb53b5..d453e3b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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;
+}