test-ioloop.c revision d54edc1ad7b71020f6726363308985e0658657fb
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2015-2016 Dovecot authors, see the included COPYING file */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen#include "test-lib.h"
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen#include "net.h"
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen#include "time-util.h"
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen#include "ioloop.h"
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen#include "istream.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen#include <unistd.h>
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstruct test_ctx {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen bool got_left;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen bool got_right;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen bool got_to;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen};
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic void timeout_callback(struct timeval *tv)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (gettimeofday(tv, NULL) < 0)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_fatal("gettimeofday() failed: %m");
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen io_loop_stop(current_ioloop);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
6e1e9e341ffe21a69a23229c2b896d03066a071eTimo Sirainenstatic void test_ioloop_fd_cb_left(struct test_ctx *ctx)
6e1e9e341ffe21a69a23229c2b896d03066a071eTimo Sirainen{
6e1e9e341ffe21a69a23229c2b896d03066a071eTimo Sirainen ctx->got_left = TRUE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (ctx->got_left && ctx->got_right)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen io_loop_stop(current_ioloop);
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic void test_ioloop_fd_cb_right(struct test_ctx *ctx)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen ctx->got_right = TRUE;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen if (ctx->got_left && ctx->got_right)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen io_loop_stop(current_ioloop);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic void test_ioloop_fd_to(struct test_ctx *ctx)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ctx->got_to = TRUE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen io_loop_stop(current_ioloop);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic void test_ioloop_fd(void)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen test_begin("ioloop fd");
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen struct test_ctx test_ctx;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen int fds[2];
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen test_assert(ret == 0);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (ret < 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_error("socketpair() failed: %m");
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen test_end();
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen memset(&test_ctx, 0, sizeof(test_ctx));
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen struct ioloop *ioloop = io_loop_create();
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen struct io *io_left =
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen io_add(fds[0], IO_READ,
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen test_ioloop_fd_cb_left, &test_ctx);
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen struct io *io_right =
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen io_add(fds[1], IO_READ,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen test_ioloop_fd_cb_right, &test_ctx);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen struct timeout *to = timeout_add(2000, test_ioloop_fd_to, &test_ctx);
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen if (write(fds[0], "ltr", 3) != 3 ||
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen write(fds[1], "rtl", 3) != 3)
0449e50c99f3fab4485f9b983e3936aaa003c79aTimo Sirainen i_fatal("write() failed: %m");
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen io_loop_run(ioloop);
6e1e9e341ffe21a69a23229c2b896d03066a071eTimo Sirainen
6e1e9e341ffe21a69a23229c2b896d03066a071eTimo Sirainen timeout_remove(&to);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen io_remove(&io_left);
8da095519878426b012058e6f331a669f327f47fTimo Sirainen io_remove(&io_right);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen test_assert(test_ctx.got_to == FALSE);
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen test_assert(test_ctx.got_left == TRUE);
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen test_assert(test_ctx.got_right == TRUE);
6e1e9e341ffe21a69a23229c2b896d03066a071eTimo Sirainen
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen io_loop_destroy(&ioloop);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_close_fd(&fds[0]);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_close_fd(&fds[1]);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen test_end();
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainenstatic void test_ioloop_timeout(void)
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainen{
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainen struct ioloop *ioloop, *ioloop2;
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen struct timeout *to, *to2;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct timeval tv_start, tv_callback;
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen test_begin("ioloop timeout");
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ioloop = io_loop_create();
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* add a timeout by moving it from another ioloop */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ioloop2 = io_loop_create();
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen to2 = timeout_add(1000, timeout_callback, &tv_callback);
208028f268ac67be00590267315bf7743db02a52Timo Sirainen io_loop_set_current(ioloop);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen to2 = io_loop_move_timeout(&to2);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen io_loop_set_current(ioloop2);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen io_loop_destroy(&ioloop2);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen sleep(1);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* add & remove immediately */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen to = timeout_add(1000, timeout_callback, &tv_callback);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen timeout_remove(&to);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen /* add the timeout we're actually testing below */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen to = timeout_add(1000, timeout_callback, &tv_callback);
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen if (gettimeofday(&tv_start, NULL) < 0)
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen i_fatal("gettimeofday() failed: %m");
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen io_loop_run(ioloop);
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen test_assert(timeval_diff_msecs(&tv_callback, &tv_start) >= 500);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen timeout_remove(&to);
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen timeout_remove(&to2);
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen io_loop_destroy(&ioloop);
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen test_end();
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen}
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic void io_callback(void *context ATTR_UNUSED)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic void test_ioloop_find_fd_conditions(void)
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen enum io_condition condition;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen int fd[2];
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct io *io;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } tests[] = {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen { IO_ERROR, { -1, -1 }, NULL },
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen { IO_READ, { -1, -1 }, NULL },
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen { IO_WRITE, { -1, -1 }, NULL },
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen { IO_READ | IO_WRITE, { -1, -1 }, NULL },
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen { IO_READ, { -1, -1 }, NULL } /* read+write as separate ios */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen };
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct ioloop *ioloop;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct io *io;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen unsigned int i;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen test_begin("ioloop find fd conditions");
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ioloop = io_loop_create();
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen for (i = 0; i < N_ELEMENTS(tests); i++) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (socketpair(AF_UNIX, SOCK_STREAM, 0, tests[i].fd) < 0)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_fatal("socketpair() failed: %m");
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen tests[i].io = io_add(tests[i].fd[0], tests[i].condition, io_callback, (void *)NULL);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen io = io_add(tests[i-1].fd[0], IO_WRITE, io_callback, (void *)NULL);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen tests[i-1].condition |= IO_WRITE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen for (i = 0; i < N_ELEMENTS(tests); i++)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen test_assert_idx(io_loop_find_fd_conditions(ioloop, tests[i].fd[0]) == tests[i].condition, i);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen io_remove(&io);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen for (i = 0; i < N_ELEMENTS(tests); i++) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen io_remove(&tests[i].io);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_close_fd(&tests[i].fd[0]);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen i_close_fd(&tests[i].fd[1]);
32d69cb0794acf725c47e6d17145ec4eb0cd6e7fTimo Sirainen }
32d69cb0794acf725c47e6d17145ec4eb0cd6e7fTimo Sirainen io_loop_destroy(&ioloop);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen test_end();
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic void io_callback_pending_io(void *context ATTR_UNUSED)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen io_loop_stop(current_ioloop);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic void test_ioloop_pending_io(void)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen test_begin("ioloop pending io");
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct istream *is = i_stream_create_from_data("data", 4);
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen struct ioloop *ioloop = io_loop_create();
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct io *io = io_add_istream(is, io_callback_pending_io, NULL);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen io_loop_set_current(ioloop);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen io_set_pending(io);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen io_loop_run(ioloop);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen io_remove(&io);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_stream_unref(&is);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen io_loop_destroy(&ioloop);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen test_end();
008c010ed99d23ff601c8aec48c27781dd1c6015Timo Sirainen}
008c010ed99d23ff601c8aec48c27781dd1c6015Timo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenvoid test_ioloop(void)
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen test_ioloop_timeout();
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen test_ioloop_find_fd_conditions();
8d35582f2577c64517b2341c5d6477c7010e0a0cPhil Carmody test_ioloop_pending_io();
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen test_ioloop_fd();
008c010ed99d23ff601c8aec48c27781dd1c6015Timo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen