aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/liberty.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/tests/liberty.c b/tests/liberty.c
index 3676a45..0925b05 100644
--- a/tests/liberty.c
+++ b/tests/liberty.c
@@ -462,6 +462,162 @@ test_async (void)
async_manager_free (&data.manager);
}
+// --- Connector ---------------------------------------------------------------
+
+// This also happens to test a large part of the poller implementation
+
+#include <arpa/inet.h>
+
+struct test_connector_fixture
+{
+ const char *host; ///< The host we're listening on
+ int port; ///< The port we're listening on
+
+ int listening_fd; ///< Listening FD
+
+ struct poller poller; ///< Poller
+ struct poller_fd listening_event; ///< Listening event
+ bool quitting; ///< Quit signal for the event loop
+};
+
+static void
+test_connector_on_client (const struct pollfd *pfd, void *user_data)
+{
+ (void) user_data;
+
+ int fd = accept (pfd->fd, NULL, NULL);
+ if (fd == -1)
+ {
+ if (errno == EAGAIN
+ || errno == EINTR
+ || errno == ECONNABORTED)
+ return;
+
+ exit_fatal ("%s: %s", "accept", strerror (errno));
+ }
+
+ const char message[] = "Hello!\n";
+ (void) write (fd, message, strlen (message));
+ xclose (fd);
+}
+
+static bool
+test_connector_try_bind
+ (struct test_connector_fixture *self, const char *host, int port)
+{
+ struct sockaddr_in sin;
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons ((self->port = port));
+ sin.sin_addr.s_addr = inet_addr ((self->host = host));
+
+ int fd = socket (AF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ return true;
+
+ int yes = 1;
+ (void) setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
+
+ if (bind (fd, (struct sockaddr *) &sin, sizeof sin)
+ || listen (fd, 10))
+ {
+ xclose (fd);
+ return false;
+ }
+
+ self->listening_fd = fd;
+ return true;
+}
+
+static void
+test_connector_fixture_init
+ (const void *user_data, struct test_connector_fixture *self)
+{
+ (void) user_data;
+
+ // Find a free port on localhost in the user range and bind to it
+ for (int i = 0; i < 1024; i++)
+ if (test_connector_try_bind (self, "127.0.0.1", 1024 + i))
+ break;
+ if (!self->listening_fd)
+ exit_fatal ("cannot bind to localhost");
+
+ // Make it so that we immediately accept all connections
+ poller_init (&self->poller);
+ poller_fd_init (&self->listening_event, &self->poller, self->listening_fd);
+ self->listening_event.dispatcher = test_connector_on_client;
+ self->listening_event.user_data = (poller_fd_fn) self;
+ poller_fd_set (&self->listening_event, POLLIN);
+}
+
+static void
+test_connector_fixture_free
+ (const void *user_data, struct test_connector_fixture *self)
+{
+ (void) user_data;
+
+ poller_free (&self->poller);
+ xclose (self->listening_fd);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+static void
+test_connector_on_connected (void *user_data, int socket, const char *hostname)
+{
+ struct test_connector_fixture *self = user_data;
+ hard_assert (!strcmp (hostname, self->host));
+ xclose (socket);
+
+ self->quitting = true;
+}
+
+static void
+test_connector_on_failure (void *user_data)
+{
+ (void) user_data;
+ exit_fatal ("failed to connect to the prepared port");
+}
+
+static void
+test_connector_on_connecting (void *user_data, const char *address)
+{
+ (void) user_data;
+ print_debug ("connecting to %s", address);
+}
+
+static void
+test_connector_on_error (void *user_data, const char *error)
+{
+ (void) user_data;
+ print_debug ("%s: %s", "connecting failed", error);
+}
+
+static void
+test_connector (const void *user_data, struct test_connector_fixture *self)
+{
+ (void) user_data;
+ print_debug ("final target is %s:%d", self->host, self->port);
+
+ struct connector connector;
+ connector_init (&connector, &self->poller);
+ connector.on_connecting = test_connector_on_connecting;
+ connector.on_error = test_connector_on_error;
+ connector.on_connected = test_connector_on_connected;
+ connector.on_failure = test_connector_on_failure;
+ connector.user_data = self;
+
+ connector_add_target (&connector, ":D", "nonsense");
+
+ char *port = xstrdup_printf ("%d", self->port);
+ connector_add_target (&connector, self->host, port);
+ free (port);
+
+ while (!self->quitting)
+ poller_run (&self->poller);
+
+ connector_free (&connector);
+}
+
// --- Main --------------------------------------------------------------------
int
@@ -481,6 +637,11 @@ main (int argc, char *argv[])
test_add_simple (&test, "/base64", NULL, test_base64);
test_add_simple (&test, "/async", NULL, test_async);
+ test_add (&test, "/connector", struct test_connector_fixture, NULL,
+ test_connector_fixture_init,
+ test_connector,
+ test_connector_fixture_free);
+
// TODO: write tests for the rest of the library
return test_run (&test);