aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax <msuraev@sysmocom.de>2019-02-06 10:58:42 +0100
committerMax <msuraev@sysmocom.de>2019-02-07 13:44:30 +0100
commitfe3527da2ac691c961f767c97d70bfe00d1e4d10 (patch)
tree1835eb5c27723308e394c0f1f33faf11ce5c57f4
parent1a357720b56386c0d42c3a6dccfff11f46cf27e7 (diff)
Add stream client/server test
Previously stream client and server code were only used in examples which means regressions could be easily introduced unnoticed until they trigger bugs in external code which relies on osmo_stream_*() Fix this by adding basic client-server interaction tests with and without reconnection. Change-Id: I336f79970982ed8e1d73b73d54fa4c27ba8bce8e
-rw-r--r--.gitignore1
-rw-r--r--tests/Makefile.am8
-rw-r--r--tests/stream/stream_test.c309
-rw-r--r--tests/stream/stream_test.err43
-rw-r--r--tests/stream/stream_test.ok51
-rw-r--r--tests/testsuite.at7
6 files changed, 418 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index 672708d..e2f2fb9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,3 +56,4 @@ Doxyfile
jibuf_test
jibuf_tool
osmux_test2
+stream_test
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 03a7a3c..c3628ac 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,7 +1,7 @@
AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) -g
AM_LDFLAGS = $(LIBOSMOCORE_LDFLAGS)
-check_PROGRAMS = osmux/osmux_test osmux/osmux_test2 jibuf/jibuf_test
+check_PROGRAMS = osmux/osmux_test osmux/osmux_test2 stream/stream_test jibuf/jibuf_test
check_HEADERS =
osmux_osmux_test_SOURCES = osmux/osmux_test.c
@@ -10,6 +10,10 @@ osmux_osmux_test_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(top_builddir)/
osmux_osmux_test2_SOURCES = osmux/osmux_test2.c
osmux_osmux_test2_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(top_builddir)/src/libosmonetif.la
+stream_stream_test_SOURCES = stream/stream_test.c
+stream_stream_test_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(top_builddir)/src/libosmonetif.la
+stream_stream_test_LDFLAGS = -no-install
+
jibuf_jibuf_test_SOURCES = jibuf/jibuf_test.c
jibuf_jibuf_test_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(top_builddir)/src/libosmonetif.la
@@ -57,6 +61,8 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \
osmux/osmux_test.ok \
osmux/osmux_test2.ok \
+ stream/stream_test.ok \
+ stream/stream_test.err \
jibuf/jibuf_test.ok
DISTCLEANFILES = atconfig
diff --git a/tests/stream/stream_test.c b/tests/stream/stream_test.c
new file mode 100644
index 0000000..1a0c555
--- /dev/null
+++ b/tests/stream/stream_test.c
@@ -0,0 +1,309 @@
+/*
+ * (C) 2019 by sysmocom - s.f.m.c. GmbH.
+ * Author: Max Suraev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <osmocom/core/select.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/application.h>
+
+#include <osmocom/netif/stream.h>
+
+#define DSTREAMTEST 0
+struct log_info_cat osmo_stream_test_cat[] = {
+ [DSTREAMTEST] = {
+ .name = "DSTREAMTEST",
+ .description = "STREAM test",
+ .enabled = 1, .loglevel = LOGL_INFO,
+ },
+};
+
+const struct log_info osmo_stream_test_log_info = {
+ .filter_fn = NULL,
+ .cat = osmo_stream_test_cat,
+ .num_cat = ARRAY_SIZE(osmo_stream_test_cat),
+};
+
+static struct msgb *make_msgb(const char *m)
+{
+ struct msgb *msg = msgb_alloc(512, "STREAM test");
+ if (!msg) {
+ printf("Unable to allocate message\n");
+ return NULL;
+ }
+
+ if (m)
+ msgb_printf(msg, "%s", m);
+
+ return msg;
+}
+
+#define ASTR(rec) ((rec) ? "autoreconnecting" : "non-reconnecting")
+
+/* client defs */
+#define LOGCLI(cli, fmt, args...) \
+ printf("[%s] Client's %s(): " fmt, osmo_stream_cli_get_data(cli) ? "OK" : "NA", __func__, ##args)
+
+#define CLI_SND(cli, m) do { \
+ struct msgb *msg = make_msgb(m); \
+ LOGCLI(cli, "sent %d bytes message: %s\n", \
+ msg->len, msgb_hexdump(msg)); \
+ osmo_stream_cli_send(cli, msg); \
+ } while(0)
+
+/* client callbacks */
+static int connect_cb_cli(struct osmo_stream_cli *cli)
+{
+ void *recon = osmo_stream_cli_get_data(cli);
+ LOGCLI(cli, "callback triggered <%s>\n", recon ? "reconnected" : "initial");
+ if (recon) {
+ LOGCLI(cli, "closing connection\n");
+ osmo_stream_cli_close(cli);
+ } else
+ CLI_SND(cli, "Hi! from connect callback :-P");
+
+ return 0;
+}
+
+static int read_cb_cli(struct osmo_stream_cli *cli)
+{
+ int bytes;
+ void *cli_data = osmo_stream_cli_get_data(cli);
+ struct msgb *msg = make_msgb(NULL);
+ if (!msg)
+ return -ENOMEM;
+
+ LOGCLI(cli, "callback triggered\n");
+
+ bytes = osmo_stream_cli_recv(cli, msg);
+ if (bytes < 0) {
+ LOGCLI(cli, "unable to receive message\n");
+ return -EINVAL;
+ }
+
+ if (bytes)
+ LOGCLI(cli, "received %d(%d) bytes: %s\n", bytes, msg->len, msgb_hexdump(msg));
+ else {
+ /* N. B: normally receiving 0 bytes means that we should close the connection and re-establish it
+ but to test autoreconnection logic we ignore it in here to let the test run till completion */
+ LOGCLI(cli, "0-byte read, auto-reconnect will be triggered if enabled\n");
+ }
+
+ if (!cli_data) {
+ LOGCLI(cli, "initial read, contacting server\n");
+
+ osmo_stream_cli_set_data(cli, msg);
+ CLI_SND(cli, "Doh, responding to server :-D");
+ }
+
+ return 0;
+}
+
+/* client helpers */
+static struct osmo_stream_cli *init_client_reconnection(struct osmo_stream_cli *cli, bool autoreconnect)
+{
+ /* setting negative timeout ensures that we disable reconnection logic */
+ osmo_stream_cli_set_reconnect_timeout(cli, autoreconnect ? 9 : -1);
+
+ if (osmo_stream_cli_open(cli) < 0) {
+ LOGCLI(cli, "unable to open client\n");
+ return NULL;
+ }
+
+ return cli;
+}
+
+static struct osmo_stream_cli *make_client(void *ctx, const char *host, unsigned port, bool autoreconnect)
+{
+ struct osmo_stream_cli *cli = osmo_stream_cli_create(ctx);
+ if (!cli) {
+ printf("Unable to create client\n");
+ return NULL;
+ }
+
+ printf("Prepare %s stream client...\n", ASTR(autoreconnect));
+
+ osmo_stream_cli_set_addr(cli, host);
+ osmo_stream_cli_set_port(cli, port);
+ osmo_stream_cli_set_connect_cb(cli, connect_cb_cli);
+ osmo_stream_cli_set_read_cb(cli, read_cb_cli);
+
+ return init_client_reconnection(cli, autoreconnect);
+}
+
+/* server defs */
+#define LOGLNK(lnk, fmt, args...) \
+ printf("[%s] Server's %s(): " fmt, osmo_stream_srv_link_get_data(lnk) ? "OK" : "NA", __func__, ##args)
+
+#define LOGSRV(srv, fmt, args...) \
+ printf("[%s|%s] Server's %s(): " fmt, osmo_stream_srv_get_data(srv) ? "OK" : "NA", \
+ osmo_stream_srv_link_get_data(osmo_stream_srv_get_master(srv)) ? "OK" : "NA", __func__, ##args)
+
+#define SRV_SND(srv, m) do { \
+ struct msgb *msg = make_msgb(m); \
+ LOGSRV(srv, "sent %d bytes message: %s\n", \
+ msg->len, msgb_hexdump(msg)); \
+ osmo_stream_srv_send(srv, msg); \
+ } while(0)
+
+/* server helpers */
+static bool subsequent_read(struct osmo_stream_srv *srv)
+{
+ if (osmo_stream_srv_get_data(srv))
+ return true;
+
+ osmo_stream_srv_set_data(srv, srv);
+
+ return false;
+}
+
+static void request_test_stop(struct osmo_stream_srv *srv)
+{
+ osmo_stream_srv_link_set_data(osmo_stream_srv_get_master(srv), NULL);
+}
+
+static bool test_stop_requested(struct osmo_stream_srv_link *lnk)
+{
+ if (osmo_stream_srv_link_get_data(lnk))
+ return false;
+ return true;
+}
+
+/* server callbacks */
+int read_cb_srv(struct osmo_stream_srv *srv)
+{
+ int bytes;
+ struct msgb *msg = make_msgb(NULL);
+ if (!msg)
+ return -ENOMEM;
+
+ LOGSRV(srv, "callback triggered\n");
+
+ bytes = osmo_stream_srv_recv(srv, msg);
+ if (bytes <= 0) {
+ if (bytes < 0)
+ LOGSRV(srv, "unable to receive message: %s\n", strerror(-bytes));
+ else {
+ LOGSRV(srv, "client have already closed connection\n");
+
+ /* if client have already closed the connection,
+ than it must be subsequent (after reconnect) call */
+ request_test_stop(srv);
+ }
+ osmo_stream_srv_destroy(srv);
+ return -EINVAL;
+ } else {
+ LOGSRV(srv, "received %d(%d) bytes: %s\n", bytes, msg->len, msgb_hexdump(msg));
+ SRV_SND(srv, __func__);
+ }
+
+ msgb_free(msg);
+
+ if (subsequent_read(srv)) {
+ LOGSRV(srv, "force client disconnect on subsequent call\n");
+ osmo_stream_srv_destroy(srv);
+ } else
+ LOGSRV(srv, "keep initial client connection\n");
+
+ return 0;
+}
+
+static int close_cb_srv(struct osmo_stream_srv *ignored)
+{
+ return 0;
+}
+
+static int accept_cb_srv(struct osmo_stream_srv_link *lnk, int fd)
+{
+ struct osmo_stream_srv *srv = osmo_stream_srv_create(osmo_stream_srv_link_get_data(lnk), lnk, fd,
+ read_cb_srv, close_cb_srv, NULL);
+ if (!srv) {
+ LOGLNK(lnk, "error while creating connection\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static void test_recon(void *ctx, const char *host, unsigned port, unsigned steps, struct osmo_stream_srv_link *lnk,
+ bool autoreconnect)
+{
+ struct osmo_stream_cli *cli = make_client(ctx, host, port, autoreconnect);
+ if (!cli)
+ return;
+
+ printf("=======================================\n");
+ printf("Client/Server entering %s event loop...\n", ASTR(autoreconnect));
+ printf("=======================================\n");
+
+ osmo_stream_srv_link_set_data(lnk, ctx);
+
+ while(steps--) {
+ osmo_select_main(0);
+ fprintf(stderr, "\n%s test step %u [client %s, server %s], FD reg %u\n", ASTR(autoreconnect), steps,
+ osmo_stream_cli_get_data(cli) ? "OK" : "NA",
+ osmo_stream_srv_link_get_data(lnk) ? "OK" : "NA",
+ osmo_fd_is_registered(osmo_stream_cli_get_ofd(cli)));
+
+ if (test_stop_requested(lnk)) {
+ printf("Server requested test termination\n");
+ steps = 0;
+ }
+ }
+
+ osmo_stream_cli_destroy(cli);
+ printf("%s test complete.\n\n", ASTR(autoreconnect));
+}
+
+
+int main(void)
+{
+ struct osmo_stream_srv_link *srv;
+ char *host = "127.0.0.11";
+ unsigned port = 1111;
+ void *tall_test = talloc_named_const(NULL, 1, "osmo_stream_test");
+ msgb_talloc_ctx_init(tall_test, 0);
+ osmo_init_logging2(tall_test, &osmo_stream_test_log_info);
+ log_set_log_level(osmo_stderr_target, LOGL_INFO);
+ log_set_use_color(osmo_stderr_target, 0);
+ log_set_print_category_hex(osmo_stderr_target, 0);
+ log_set_print_filename(osmo_stderr_target, 0);
+
+ printf("Preparing stream server...\n");
+ srv = osmo_stream_srv_link_create(tall_test);
+ if (!srv) {
+ printf("Unable to create server\n");
+ return EXIT_FAILURE;
+ }
+
+ osmo_stream_srv_link_set_addr(srv, host);
+ osmo_stream_srv_link_set_port(srv, port);
+ osmo_stream_srv_link_set_accept_cb(srv, accept_cb_srv);
+
+ if (osmo_stream_srv_link_open(srv) < 0) {
+ printf("Unable to open server\n");
+ return EXIT_FAILURE;
+ }
+
+ test_recon(tall_test, host, port, 12, srv, true);
+ test_recon(tall_test, host, port, 8, srv, false);
+
+ osmo_stream_srv_link_destroy(srv);
+ printf("Stream tests completed\n");
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/stream/stream_test.err b/tests/stream/stream_test.err
new file mode 100644
index 0000000..07cc7b0
--- /dev/null
+++ b/tests/stream/stream_test.err
@@ -0,0 +1,43 @@
+
+autoreconnecting test step 11 [client NA, server OK], FD reg 1
+
+autoreconnecting test step 10 [client NA, server OK], FD reg 1
+
+autoreconnecting test step 9 [client NA, server OK], FD reg 1
+
+autoreconnecting test step 8 [client NA, server OK], FD reg 1
+
+autoreconnecting test step 7 [client OK, server OK], FD reg 1
+
+autoreconnecting test step 6 [client OK, server OK], FD reg 1
+
+autoreconnecting test step 5 [client OK, server OK], FD reg 1
+[ CONNECTED] osmo_stream_cli_recv(): connection closed with srv
+[ NONE] osmo_stream_cli_reconnect(): retrying in 9 seconds...
+
+autoreconnecting test step 4 [client OK, server OK], FD reg 0
+
+autoreconnecting test step 3 [client OK, server OK], FD reg 1
+
+autoreconnecting test step 2 [client OK, server OK], FD reg 0
+connection closed with srv
+
+autoreconnecting test step 1 [client OK, server NA], FD reg 0
+
+non-reconnecting test step 7 [client NA, server OK], FD reg 1
+
+non-reconnecting test step 6 [client NA, server OK], FD reg 1
+
+non-reconnecting test step 5 [client NA, server OK], FD reg 1
+
+non-reconnecting test step 4 [client NA, server OK], FD reg 1
+
+non-reconnecting test step 3 [client OK, server OK], FD reg 1
+
+non-reconnecting test step 2 [client OK, server OK], FD reg 1
+
+non-reconnecting test step 1 [client OK, server OK], FD reg 1
+[ CONNECTED] osmo_stream_cli_recv(): connection closed with srv
+[ NONE] osmo_stream_cli_reconnect(): not reconnecting, disabled.
+
+non-reconnecting test step 0 [client OK, server OK], FD reg 0
diff --git a/tests/stream/stream_test.ok b/tests/stream/stream_test.ok
new file mode 100644
index 0000000..7b6fb95
--- /dev/null
+++ b/tests/stream/stream_test.ok
@@ -0,0 +1,51 @@
+Preparing stream server...
+Prepare autoreconnecting stream client...
+=======================================
+Client/Server entering autoreconnecting event loop...
+=======================================
+[NA] Client's connect_cb_cli(): callback triggered <initial>
+[NA] Client's connect_cb_cli(): sent 29 bytes message: 48 69 21 20 66 72 6f 6d 20 63 6f 6e 6e 65 63 74 20 63 61 6c 6c 62 61 63 6b 20 3a 2d 50
+[NA|OK] Server's read_cb_srv(): callback triggered
+[NA|OK] Server's read_cb_srv(): received 29(29) bytes: 48 69 21 20 66 72 6f 6d 20 63 6f 6e 6e 65 63 74 20 63 61 6c 6c 62 61 63 6b 20 3a 2d 50
+[NA|OK] Server's read_cb_srv(): sent 11 bytes message: 72 65 61 64 5f 63 62 5f 73 72 76
+[OK|OK] Server's read_cb_srv(): keep initial client connection
+[NA] Client's read_cb_cli(): callback triggered
+[NA] Client's read_cb_cli(): received 11(11) bytes: 72 65 61 64 5f 63 62 5f 73 72 76
+[NA] Client's read_cb_cli(): initial read, contacting server
+[OK] Client's read_cb_cli(): sent 29 bytes message: 44 6f 68 2c 20 72 65 73 70 6f 6e 64 69 6e 67 20 74 6f 20 73 65 72 76 65 72 20 3a 2d 44
+[OK|OK] Server's read_cb_srv(): callback triggered
+[OK|OK] Server's read_cb_srv(): received 29(29) bytes: 44 6f 68 2c 20 72 65 73 70 6f 6e 64 69 6e 67 20 74 6f 20 73 65 72 76 65 72 20 3a 2d 44
+[OK|OK] Server's read_cb_srv(): sent 11 bytes message: 72 65 61 64 5f 63 62 5f 73 72 76
+[OK|OK] Server's read_cb_srv(): force client disconnect on subsequent call
+[OK] Client's read_cb_cli(): callback triggered
+[OK] Client's read_cb_cli(): 0-byte read, auto-reconnect will be triggered if enabled
+[OK] Client's connect_cb_cli(): callback triggered <reconnected>
+[OK] Client's connect_cb_cli(): closing connection
+[NA|OK] Server's read_cb_srv(): callback triggered
+[NA|OK] Server's read_cb_srv(): client have already closed connection
+Server requested test termination
+autoreconnecting test complete.
+
+Prepare non-reconnecting stream client...
+=======================================
+Client/Server entering non-reconnecting event loop...
+=======================================
+[NA] Client's connect_cb_cli(): callback triggered <initial>
+[NA] Client's connect_cb_cli(): sent 29 bytes message: 48 69 21 20 66 72 6f 6d 20 63 6f 6e 6e 65 63 74 20 63 61 6c 6c 62 61 63 6b 20 3a 2d 50
+[NA|OK] Server's read_cb_srv(): callback triggered
+[NA|OK] Server's read_cb_srv(): received 29(29) bytes: 48 69 21 20 66 72 6f 6d 20 63 6f 6e 6e 65 63 74 20 63 61 6c 6c 62 61 63 6b 20 3a 2d 50
+[NA|OK] Server's read_cb_srv(): sent 11 bytes message: 72 65 61 64 5f 63 62 5f 73 72 76
+[OK|OK] Server's read_cb_srv(): keep initial client connection
+[NA] Client's read_cb_cli(): callback triggered
+[NA] Client's read_cb_cli(): received 11(11) bytes: 72 65 61 64 5f 63 62 5f 73 72 76
+[NA] Client's read_cb_cli(): initial read, contacting server
+[OK] Client's read_cb_cli(): sent 29 bytes message: 44 6f 68 2c 20 72 65 73 70 6f 6e 64 69 6e 67 20 74 6f 20 73 65 72 76 65 72 20 3a 2d 44
+[OK|OK] Server's read_cb_srv(): callback triggered
+[OK|OK] Server's read_cb_srv(): received 29(29) bytes: 44 6f 68 2c 20 72 65 73 70 6f 6e 64 69 6e 67 20 74 6f 20 73 65 72 76 65 72 20 3a 2d 44
+[OK|OK] Server's read_cb_srv(): sent 11 bytes message: 72 65 61 64 5f 63 62 5f 73 72 76
+[OK|OK] Server's read_cb_srv(): force client disconnect on subsequent call
+[OK] Client's read_cb_cli(): callback triggered
+[OK] Client's read_cb_cli(): 0-byte read, auto-reconnect will be triggered if enabled
+non-reconnecting test complete.
+
+Stream tests completed
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 67b91c6..8eb389d 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -1,6 +1,13 @@
AT_INIT
AT_BANNER([Regression tests.])
+AT_SETUP([stream_test])
+AT_KEYWORDS([stream_test])
+cat $abs_srcdir/stream/stream_test.ok > expout
+cat $abs_srcdir/stream/stream_test.err > experr
+AT_CHECK([$abs_top_builddir/tests/stream/stream_test], [0], [expout], [experr])
+AT_CLEANUP
+
AT_SETUP([osmux_test])
AT_KEYWORDS([osmux_test])
cat $abs_srcdir/osmux/osmux_test.ok > expout