bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch#include "test-lib.h"
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen#include "net.h"
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch#include "time-util.h"
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch#include "ioloop.h"
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi#include "istream.h"
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch#include <unistd.h>
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomistruct test_ctx {
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi bool got_left;
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi bool got_right;
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi bool got_to;
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi};
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Boschstatic void timeout_callback(struct timeval *tv)
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch{
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch if (gettimeofday(tv, NULL) < 0)
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch i_fatal("gettimeofday() failed: %m");
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch io_loop_stop(current_ioloop);
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch}
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomistatic void test_ioloop_fd_cb_left(struct test_ctx *ctx)
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi{
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi ctx->got_left = TRUE;
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi if (ctx->got_left && ctx->got_right)
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi io_loop_stop(current_ioloop);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi}
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomistatic void test_ioloop_fd_cb_right(struct test_ctx *ctx)
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi{
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi ctx->got_right = TRUE;
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi if (ctx->got_left && ctx->got_right)
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi io_loop_stop(current_ioloop);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi}
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomistatic void test_ioloop_fd_to(struct test_ctx *ctx)
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi{
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi ctx->got_to = TRUE;
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi io_loop_stop(current_ioloop);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi}
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomistatic void test_ioloop_fd(void)
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi{
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi test_begin("ioloop fd");
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi struct test_ctx test_ctx;
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi int fds[2];
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi test_assert(ret == 0);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi if (ret < 0) {
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi i_error("socketpair() failed: %m");
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi test_end();
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi return;
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi }
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&test_ctx);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi struct ioloop *ioloop = io_loop_create();
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi struct io *io_left =
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi io_add(fds[0], IO_READ,
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi test_ioloop_fd_cb_left, &test_ctx);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi struct io *io_right =
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi io_add(fds[1], IO_READ,
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi test_ioloop_fd_cb_right, &test_ctx);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi struct timeout *to = timeout_add(2000, test_ioloop_fd_to, &test_ctx);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
d54edc1ad7b71020f6726363308985e0658657fbTimo Sirainen if (write(fds[0], "ltr", 3) != 3 ||
d54edc1ad7b71020f6726363308985e0658657fbTimo Sirainen write(fds[1], "rtl", 3) != 3)
d54edc1ad7b71020f6726363308985e0658657fbTimo Sirainen i_fatal("write() failed: %m");
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi io_loop_run(ioloop);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi timeout_remove(&to);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi io_remove(&io_left);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi io_remove(&io_right);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi test_assert(test_ctx.got_to == FALSE);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi test_assert(test_ctx.got_left == TRUE);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi test_assert(test_ctx.got_right == TRUE);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi io_loop_destroy(&ioloop);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi i_close_fd(&fds[0]);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi i_close_fd(&fds[1]);
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi test_end();
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi}
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Boschstatic void test_ioloop_timeout(void)
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch{
9b3565b09683b48f66de51aebb52786934d1c324Timo Sirainen struct ioloop *ioloop, *ioloop2;
9b3565b09683b48f66de51aebb52786934d1c324Timo Sirainen struct timeout *to, *to2;
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch struct timeval tv_start, tv_callback;
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch test_begin("ioloop timeout");
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch ioloop = io_loop_create();
9b3565b09683b48f66de51aebb52786934d1c324Timo Sirainen
9b3565b09683b48f66de51aebb52786934d1c324Timo Sirainen /* add a timeout by moving it from another ioloop */
9b3565b09683b48f66de51aebb52786934d1c324Timo Sirainen ioloop2 = io_loop_create();
9b3565b09683b48f66de51aebb52786934d1c324Timo Sirainen to2 = timeout_add(1000, timeout_callback, &tv_callback);
9b3565b09683b48f66de51aebb52786934d1c324Timo Sirainen io_loop_set_current(ioloop);
9b3565b09683b48f66de51aebb52786934d1c324Timo Sirainen to2 = io_loop_move_timeout(&to2);
9b3565b09683b48f66de51aebb52786934d1c324Timo Sirainen io_loop_set_current(ioloop2);
9b3565b09683b48f66de51aebb52786934d1c324Timo Sirainen io_loop_destroy(&ioloop2);
9b3565b09683b48f66de51aebb52786934d1c324Timo Sirainen
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch sleep(1);
9b3565b09683b48f66de51aebb52786934d1c324Timo Sirainen
9b3565b09683b48f66de51aebb52786934d1c324Timo Sirainen /* add & remove immediately */
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch to = timeout_add(1000, timeout_callback, &tv_callback);
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch timeout_remove(&to);
9b3565b09683b48f66de51aebb52786934d1c324Timo Sirainen
9b3565b09683b48f66de51aebb52786934d1c324Timo Sirainen /* add the timeout we're actually testing below */
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch to = timeout_add(1000, timeout_callback, &tv_callback);
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch if (gettimeofday(&tv_start, NULL) < 0)
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch i_fatal("gettimeofday() failed: %m");
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch io_loop_run(ioloop);
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch test_assert(timeval_diff_msecs(&tv_callback, &tv_start) >= 500);
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch timeout_remove(&to);
9b3565b09683b48f66de51aebb52786934d1c324Timo Sirainen timeout_remove(&to2);
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch io_loop_destroy(&ioloop);
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch test_end();
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch}
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainenstatic void io_callback(void *context ATTR_UNUSED)
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen{
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen}
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainenstatic void test_ioloop_find_fd_conditions(void)
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen{
b7324e421e2132cbbf753e6fdbe675bbaecdf929Timo Sirainen static struct {
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen enum io_condition condition;
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen int fd[2];
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen struct io *io;
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen } tests[] = {
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen { IO_ERROR, { -1, -1 }, NULL },
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen { IO_READ, { -1, -1 }, NULL },
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen { IO_WRITE, { -1, -1 }, NULL },
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen { IO_READ | IO_WRITE, { -1, -1 }, NULL },
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen { IO_READ, { -1, -1 }, NULL } /* read+write as separate ios */
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen };
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen struct ioloop *ioloop;
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen struct io *io;
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen unsigned int i;
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen test_begin("ioloop find fd conditions");
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen ioloop = io_loop_create();
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen for (i = 0; i < N_ELEMENTS(tests); i++) {
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen if (socketpair(AF_UNIX, SOCK_STREAM, 0, tests[i].fd) < 0)
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen i_fatal("socketpair() failed: %m");
677b75f90d81eafe742896d6570a2f63ce501d05Josef 'Jeff' Sipek tests[i].io = io_add(tests[i].fd[0], tests[i].condition, io_callback, NULL);
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen }
677b75f90d81eafe742896d6570a2f63ce501d05Josef 'Jeff' Sipek io = io_add(tests[i-1].fd[0], IO_WRITE, io_callback, NULL);
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen tests[i-1].condition |= IO_WRITE;
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen for (i = 0; i < N_ELEMENTS(tests); i++)
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen test_assert_idx(io_loop_find_fd_conditions(ioloop, tests[i].fd[0]) == tests[i].condition, i);
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen io_remove(&io);
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen for (i = 0; i < N_ELEMENTS(tests); i++) {
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen io_remove(&tests[i].io);
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen i_close_fd(&tests[i].fd[0]);
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen i_close_fd(&tests[i].fd[1]);
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen }
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen io_loop_destroy(&ioloop);
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen test_end();
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen}
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomistatic void io_callback_pending_io(void *context ATTR_UNUSED)
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi{
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi io_loop_stop(current_ioloop);
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi}
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomistatic void test_ioloop_pending_io(void)
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi{
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi test_begin("ioloop pending io");
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi struct istream *is = i_stream_create_from_data("data", 4);
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi struct ioloop *ioloop = io_loop_create();
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi struct io *io = io_add_istream(is, io_callback_pending_io, NULL);
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi io_loop_set_current(ioloop);
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi io_set_pending(io);
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi io_loop_run(ioloop);
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi io_remove(&io);
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi i_stream_unref(&is);
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi io_loop_destroy(&ioloop);
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi test_end();
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi}
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Boschvoid test_ioloop(void)
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch{
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch test_ioloop_timeout();
7f52e276c1bf13b4809344492023b90e46c3ac5dTimo Sirainen test_ioloop_find_fd_conditions();
e5a55bb6b867ee3ed95ac216996ff2e24bd596ccAki Tuomi test_ioloop_pending_io();
cca98b5accbfff773731a206950114acb8dcacfdAki Tuomi test_ioloop_fd();
72a7c4f2ba93a723e23c941369a2985d75f240c9Stephan Bosch}