summaryrefslogtreecommitdiffstats
path: root/src/lib/test-multiplex.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/test-multiplex.c')
-rw-r--r--src/lib/test-multiplex.c167
1 files changed, 167 insertions, 0 deletions
diff --git a/src/lib/test-multiplex.c b/src/lib/test-multiplex.c
new file mode 100644
index 0000000..7f36094
--- /dev/null
+++ b/src/lib/test-multiplex.c
@@ -0,0 +1,167 @@
+/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
+
+#include "test-lib.h"
+#include "ioloop.h"
+#include "str.h"
+#include "istream.h"
+#include "istream-multiplex.h"
+#include "ostream.h"
+#include "ostream-multiplex.h"
+#include "ostream.h"
+#include "randgen.h"
+
+#include <unistd.h>
+
+struct test_channel {
+ int fds[2];
+ unsigned int cid;
+
+ struct istream *in;
+ struct ostream *out;
+ struct io *io;
+
+ struct istream *in_alt;
+ struct ostream *out_alt;
+ struct io *io_alt;
+
+ buffer_t *received;
+ buffer_t *received_alt;
+
+ unsigned int counter;
+};
+
+static struct test_channel test_channel[2];
+
+static void test_multiplex_channel_write(struct test_channel *channel)
+{
+ unsigned char buf[128];
+ size_t len = i_rand_limit(sizeof(buf));
+ random_fill(buf, len);
+ o_stream_nsend(channel->out, buf, len);
+ o_stream_nsend(channel->out_alt, buf, len);
+}
+
+static void test_multiplex_stream_write(struct ostream *channel ATTR_UNUSED)
+{
+ if (test_channel[0].received->used > 1000 &&
+ test_channel[1].received->used > 1000)
+ io_loop_stop(current_ioloop);
+ else
+ test_multiplex_channel_write(&test_channel[i_rand_limit(2)]);
+}
+
+static void test_istream_multiplex_stream_read(struct test_channel *channel)
+{
+ const unsigned char *data = NULL;
+ size_t siz = 0;
+
+ if (i_stream_read(channel->in) > 0) {
+ data = i_stream_get_data(channel->in, &siz);
+ buffer_append(channel->received, data, siz);
+ i_stream_skip(channel->in, siz);
+ }
+}
+
+static void test_istream_read_alt(struct test_channel *channel)
+{
+ const unsigned char *data = NULL;
+ size_t siz = 0;
+
+ if (i_stream_read(channel->in_alt) > 0) {
+ data = i_stream_get_data(channel->in_alt, &siz);
+ buffer_append(channel->received_alt, data, siz);
+ i_stream_skip(channel->in_alt, siz);
+ }
+}
+
+static void setup_channel(struct test_channel *channel,
+ struct istream *is, struct ostream *os)
+{
+ /* setup first channel */
+ channel->in = is;
+ channel->out = os;
+ channel->io = io_add_istream(is, test_istream_multiplex_stream_read,
+ channel);
+ test_assert(pipe(channel->fds) == 0);
+ fd_set_nonblock(channel->fds[0], TRUE);
+ fd_set_nonblock(channel->fds[1], TRUE);
+ channel->in_alt = i_stream_create_fd(channel->fds[0], SIZE_MAX);
+ channel->out_alt = o_stream_create_fd(channel->fds[1], IO_BLOCK_SIZE);
+ channel->io_alt = io_add_istream(channel->in_alt, test_istream_read_alt,
+ channel);
+ channel->received = buffer_create_dynamic(default_pool, 32768);
+ channel->received_alt = buffer_create_dynamic(default_pool, 32768);
+}
+
+static void teardown_channel(struct test_channel *channel)
+{
+ test_istream_read_alt(channel);
+ test_assert(memcmp(channel->received->data,
+ channel->received_alt->data,
+ channel->received->used) == 0);
+ test_assert(channel->received->used == channel->received_alt->used);
+
+ buffer_free(&channel->received);
+ buffer_free(&channel->received_alt);
+
+ io_remove(&channel->io);
+ io_remove(&channel->io_alt);
+ i_stream_unref(&channel->in);
+ test_assert(o_stream_finish(channel->out) > 0);
+ o_stream_unref(&channel->out);
+ i_stream_unref(&channel->in_alt);
+ test_assert(o_stream_finish(channel->out_alt) > 0);
+ o_stream_unref(&channel->out_alt);
+ i_close_fd(&channel->fds[0]);
+ i_close_fd(&channel->fds[1]);
+}
+
+static void test_multiplex_stream(void) {
+ test_begin("test multiplex (stream)");
+
+ struct ioloop *ioloop = io_loop_create();
+ io_loop_set_current(ioloop);
+
+ int fds[2];
+ test_assert(pipe(fds) == 0);
+ fd_set_nonblock(fds[0], TRUE);
+ fd_set_nonblock(fds[1], TRUE);
+ struct ostream *os = o_stream_create_fd(fds[1], SIZE_MAX);
+ struct istream *is = i_stream_create_fd(fds[0], SIZE_MAX);
+
+ struct istream *ichan0 = i_stream_create_multiplex(is, SIZE_MAX);
+ struct istream *ichan1 = i_stream_multiplex_add_channel(ichan0, 1);
+ i_stream_unref(&is);
+
+ struct ostream *ochan0 = o_stream_create_multiplex(os, 1024);
+ struct ostream *ochan1 = o_stream_multiplex_add_channel(ochan0, 1);
+ o_stream_unref(&os);
+
+ struct io *io = io_add(fds[1], IO_WRITE, test_multiplex_stream_write, os);
+
+ setup_channel(&test_channel[0], ichan0, ochan0);
+ setup_channel(&test_channel[1], ichan1, ochan1);
+
+ test_channel[0].cid = 0;
+ test_channel[1].cid = 1;
+
+ io_loop_run(current_ioloop);
+
+ io_remove(&io);
+
+ teardown_channel(&test_channel[0]);
+ teardown_channel(&test_channel[1]);
+
+ io_loop_destroy(&ioloop);
+
+ i_close_fd(&fds[0]);
+ i_close_fd(&fds[1]);
+
+ test_end();
+}
+
+void test_multiplex(void) {
+ random_init();
+ test_multiplex_stream();
+ random_deinit();
+}