Add a test for connector
This commit is contained in:
parent
385b3bdb47
commit
3f20b39b71
161
tests/liberty.c
161
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);
|
||||
|
Loading…
Reference in New Issue
Block a user