# HG changeset patch # User Tero Marttila # Date 1236880848 -7200 # Node ID 51678c7eae03fcdca595e69fb4b987bcefd9646b # Parent a4891d71aca96f3aebc0420007d0dde926cf44ac add sock_test module and some basic initial tests diff -r a4891d71aca9 -r 51678c7eae03 Makefile --- a/Makefile Thu Mar 12 18:48:42 2009 +0200 +++ b/Makefile Thu Mar 12 20:00:48 2009 +0200 @@ -28,7 +28,7 @@ EVSQL_CFLAGS = EVSQL_LDFLAGS = -levsql -lpq -BIN_NAMES = nexus +BIN_NAMES = nexus test BIN_PATHS = $(addprefix bin/,$(BIN_NAMES)) # modules @@ -36,6 +36,7 @@ CORE_OBJS = obj/error.o obj/log.o obj/chain.o SOCK_OBJS = obj/sock.o obj/sock_tcp.o +SOCK_TEST_OBJS = obj/sock_test.o SOCK_GNUTLS_OBJS = obj/sock_gnutls.o LINEPROTO_OBJS = obj/line_proto.o IRC_OBJS = obj/irc_line.o obj/irc_conn.o obj/irc_net.o obj/irc_chan.o obj/irc_cmd.o obj/irc_nm.o @@ -50,6 +51,8 @@ # binaries bin/nexus: ${CORE_OBJS} ${SOCK_OBJS} ${SOCK_GNUTLS_OBJS} ${LINEPROTO_OBJS} ${IRC_OBJS} ${IRC_LOG_OBJS} +bin/test: ${CORE_OBJS} ${SOCK_OBJS} ${SOCK_GNUTLS_OBJS} ${SOCK_TEST_OBJS} ${LINEPROTO_OBJS} ${IRC_OBJS} + # computed CFLAGS = ${MODE_CFLAGS} ${FIXED_CFLAGS} ${LIBEVENT_CFLAGS} ${GNUTLS_CFLAGS} ${EVSQL_CFLAGS} LDFLAGS = ${LIBEVENT_LDFLAGS} ${GNUTLS_LDFLAGS} ${EVSQL_LDFLAGS} diff -r a4891d71aca9 -r 51678c7eae03 src/sock.h --- a/src/sock.h Thu Mar 12 18:48:42 2009 +0200 +++ b/src/sock.h Thu Mar 12 20:00:48 2009 +0200 @@ -80,7 +80,7 @@ */ err_t sock_tcp_connect (struct sock_stream **sock_ptr, const char *host, const char *service, struct error_info *err); -/* +/** * A simple blocking SSL connect to the given host/service. The connected/handshake'd SSL socket is returned via * *sock_ptr. In case of errors, additional error information is stored in *err. * diff -r a4891d71aca9 -r 51678c7eae03 src/sock_tcp.c --- a/src/sock_tcp.c Thu Mar 12 18:48:42 2009 +0200 +++ b/src/sock_tcp.c Thu Mar 12 20:00:48 2009 +0200 @@ -120,7 +120,7 @@ /* * Our sock_stream_type */ -struct sock_stream_type sock_tcp_type = { +static struct sock_stream_type sock_tcp_type = { .methods = { .read = &sock_tcp_read, .write = &sock_tcp_write, diff -r a4891d71aca9 -r 51678c7eae03 src/sock_test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sock_test.c Thu Mar 12 20:00:48 2009 +0200 @@ -0,0 +1,170 @@ +#include "sock_test.h" + +#include +#include +#include + +static err_t sock_test_read (struct sock_stream *base_sock, void *buf_ptr, size_t *len) +{ + struct sock_test *sock = SOCK_FROM_BASE(base_sock, struct sock_test); + struct io_buf *buf = &sock->recv_buf; + struct io_vec *vec = buf->vec; + + // no current vector -> EOF + if (!vec) + return ERR_READ_EOF; + + // vector past the end -> EOF + if (vec == &buf->vecs[buf->count]) + return ERR_READ_EOF; + + // no data left in current vector -> EOF + if (buf->off >= vec->len) + return ERR_READ_EOF; + + // amount of data available in this iovec + size_t available = vec->len - buf->off; + + // amount to read + size_t to_read = *len; + + // trim down? + if (to_read > available) + to_read = available; + + // copy + memcpy(buf_ptr, vec->buf + buf->off, to_read); + + // consumed the whole vec? + if (to_read < available) { + // move offset + buf->off += to_read; + + } else { + // next vector + buf->vec++; + } + + // update len + *len = to_read; + + // ok + return SUCCESS; +} + +static err_t sock_test_write (struct sock_stream *base_sock, const void *buf_ptr, size_t *len) +{ + struct sock_test *sock = SOCK_FROM_BASE(base_sock, struct sock_test); + struct io_buf *buf = &sock->send_buf; + struct io_vec *vec = buf->vec; + + // vectors full? + if (buf->vecs == NULL || vec == &buf->vecs[buf->count]) { + size_t vec_offset = vec ? (vec - buf->vecs) : 0; + struct io_vec *v; + + // new size + buf->count = buf->count * 2 + 1; + + // grow + assert((buf->vecs = realloc(buf->vecs, buf->count * sizeof(struct io_vec)))); + + // set vec + vec = buf->vec = buf->vecs + vec_offset; + + // zero + for (v = vec; v < &buf->vecs[buf->count]; v++) { + v->buf = NULL; + v->len = 0; + } + } + + // store + vec->len = *len; + assert((vec->buf = malloc(vec->len))); + memcpy(vec->buf, buf_ptr, vec->len); + + // move vec onwards + buf->vec++; + + // ok + return SUCCESS; +} + +static err_t sock_test_event_init (struct sock_stream *base_sock) +{ + + return SUCCESS; +} + +static err_t sock_test_event_enable (struct sock_stream *base_sock, short mask) +{ + + return SUCCESS; +} + +static void sock_test_release (struct sock_stream *base_sock) +{ + +} + +/* + * Our sock_stream_type + */ +static struct sock_stream_type sock_test_type = { + .methods = { + .read = &sock_test_read, + .write = &sock_test_write, + .event_init = &sock_test_event_init, + .event_enable = &sock_test_event_enable, + .release = &sock_test_release, + }, +}; + +struct sock_test* sock_test_create (void) +{ + struct sock_test *sock; + + // allocate + assert((sock = calloc(1, sizeof(*sock)))); + + // initialize base with our sock_stream_type + sock_stream_init(SOCK_TEST_BASE(sock), &sock_test_type); + + // ok + return sock; +} + +void sock_test_set_recv_buffer (struct sock_test *sock, struct io_vec *vecs, size_t count) +{ + sock->recv_buf.vecs = vecs; + sock->recv_buf.count = count; + sock->recv_buf.vec = vecs; + sock->recv_buf.off = 0; +} + +void sock_test_get_send_data (struct sock_test *sock, char **buf_ptr, size_t *len_ptr) +{ + struct io_buf *buf = &sock->send_buf; + size_t len = 0, i, off = 0; + char *out; + + // calculate total size + for (i = 0; i < buf->count; i++) { + len += buf->vecs[i].len; + } + + // alloc + assert((out = malloc(len))); + + // copy + for (i = 0; i < buf->count; i++) { + memcpy(out + off, buf->vecs[i].buf, buf->vecs[i].len); + off += buf->vecs[i].len; + } + + // update return + *buf_ptr = out; + *len_ptr = len; +} + diff -r a4891d71aca9 -r 51678c7eae03 src/sock_test.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sock_test.h Thu Mar 12 20:00:48 2009 +0200 @@ -0,0 +1,72 @@ +#ifndef SOCK_TEST_H +#define SOCK_TEST_H + +/** + * @file + * + * Dummy sock_stream implemention for local testing. + */ +#include "sock_internal.h" + +/** + * IO vector + */ +struct io_vec { + /** The buffer */ + char *buf; + + /** Buffer size */ + size_t len; +}; + +/** + * Vectored IO-buffer + */ +struct io_buf { + /** The array of buffer-vectors, {NULL}-terminated */ + struct io_vec *vecs; + + /** The number of io_vecs */ + size_t count; + + /** Current vector */ + struct io_vec *vec; + + /** Offset into current vector */ + size_t off; +}; + +/** + * The per-socket state + */ +struct sock_test { + /** The base struct for sock_stream_* functions */ + struct sock_stream base; + + /** The send/recieve buffers */ + struct io_buf send_buf, recv_buf; +}; + +/** + * Get a sock_stream pointer from a sock_tcp pointer + */ +#define SOCK_TEST_BASE(sock_ptr) (&(sock_ptr)->base) + +/** + * A dummy stream socket intended for testing purposes. + */ +struct sock_test* sock_test_create (void); + +/** + * Set the recieve buffer contents. + * + * The data is not copied, but the vectors are stored as-is. + */ +void sock_test_set_recv_buffer (struct sock_test *sock, struct io_vec *vecs, size_t count); + +/** + * Get the send buffer contents as a single string, free() after use if you care about that + */ +void sock_test_get_send_data (struct sock_test *sock, char **buf, size_t *len); + +#endif diff -r a4891d71aca9 -r 51678c7eae03 src/test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test.c Thu Mar 12 20:00:48 2009 +0200 @@ -0,0 +1,118 @@ +/** + * The main test code entry point + */ +#include "sock_test.h" +#include "irc_conn.h" +#include "log.h" + +#include +#include + +void assert_sock_read (struct sock_stream *sock, const char *str) +{ + char buf[strlen(str)]; + + log_debug("read: %p: '%s'", sock, str); + + // read it + assert(sock_stream_read(sock, buf, strlen(str)) == (int) strlen(str)); + + // cmp + assert(strncmp(buf, str, strlen(str)) == 0); +} + +void assert_sock_write (struct sock_stream *sock, const char *str) +{ + log_debug("write: %p: '%s'", sock, str); + + // write it + assert(sock_stream_write(sock, str, strlen(str)) == (int) strlen(str)); +} + +void test_sock_test (void) +{ + struct sock_test *sock = sock_test_create(); + struct io_vec _read_data[] = { + { "foo", 3 }, + { "barx", 4 } + }; + const char *_write_data = "test data"; + + // put the read data + log_debug("set_recv_buffer: %p, %d", _read_data, 2); + sock_test_set_recv_buffer(sock, _read_data, 2); + + // read it out + assert_sock_read(SOCK_TEST_BASE(sock), "foo"); + assert_sock_read(SOCK_TEST_BASE(sock), "ba"); + assert_sock_read(SOCK_TEST_BASE(sock), "rx"); + + // write the data in + assert_sock_write(SOCK_TEST_BASE(sock), "test "); + assert_sock_write(SOCK_TEST_BASE(sock), "data"); + + // get the data out + char *data; + size_t len; + + sock_test_get_send_data(sock, &data, &len); + + log_debug("get_send_data: %u: '%s'", len, data); + + // should be the same + assert(len == strlen(_write_data)); + assert(strncmp(data, _write_data, len) == 0); +} + +static struct irc_conn_callbacks _conn_callbacks = { + .on_registered = NULL, +}; + +void test_irc_conn (void) +{ + struct sock_test *sock; + struct irc_conn *conn; + struct error_info err; + + // create the test socket + assert((sock = sock_test_create())); + + // create the irc_conn + assert(irc_conn_create(&conn, SOCK_TEST_BASE(sock), &_conn_callbacks, NULL, &err) == SUCCESS); + + // destroy it + irc_conn_destroy(conn); +} + +/** + * Test definition + */ +static struct test { + /** Test name */ + const char *name; + + /** Test func */ + void (*func) (void); + +} _tests[] = { + { "sock_test", &test_sock_test }, + { "irc_conn", &test_irc_conn }, + { NULL, NULL } +}; + +int main (int argc, char **argv) +{ + struct test *test; + + (void) argv; + + // no arguments + assert(argc == 1); + + // run tests + for (test = _tests; test->name; test++) { + log_info("Running test: %s", test->name); + + test->func(); + } +}