bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi */
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi#include "lib.h"
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi#include "test-lib.h"
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi#include "mempool.h"
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi#include "buffer.h"
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi#include "str.h"
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi#include "array.h"
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi#include "istream.h"
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi#include "ostream.h"
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi#include "istream-dot.h"
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi#include "ostream-dot.h"
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi#include "net.h"
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi#include "iostream-temp.h"
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi#include "program-client.h"
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi#include <unistd.h>
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomistatic const char *pclient_test_io_string = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\r\n"
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi "Praesent vehicula ac leo vel placerat. Nullam placerat \r\n"
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi "volutpat leo, sed ultricies felis pulvinar quis. Nam \r\n"
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi "tempus, augue ut tempor cursus, neque felis commodo lacus, \r\n"
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi "sit amet tincidunt arcu justo vel augue. Proin dapibus \r\n"
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi "vulputate maximus. Mauris congue lacus felis, sed varius \r\n"
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi "leo finibus sagittis. Cum sociis natoque penatibus et magnis \r\n"
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi "dis parturient montes, nascetur ridiculus mus. Aliquam \r\n"
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi "laoreet arcu a hendrerit consequat. Duis vitae erat tellus.";
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistruct program_client_settings pc_set = {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi .client_connect_timeout_msecs = 5000,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi .input_idle_timeout_msecs = 10000,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi .debug = TRUE,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi};
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistruct test_server {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct ioloop *ioloop;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct io *io;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct timeout *to;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct test_client *client;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi int listen_fd;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi in_port_t port;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi unsigned int io_loop_ref;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi} test_globals;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistruct test_client {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi pool_t pool;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi int fd;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct io *io;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct istream *in;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct ostream *out;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct ostream *os_body;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct istream *body;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi ARRAY_TYPE(const_string) args;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi enum {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi CLIENT_STATE_INIT,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi CLIENT_STATE_VERSION,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi CLIENT_STATE_ARGS,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi CLIENT_STATE_BODY
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi } state;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi};
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomivoid test_program_io_loop_run(void)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi{
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (test_globals.io_loop_ref++ == 0)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi io_loop_run(current_ioloop);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi}
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomivoid test_program_io_loop_stop(void)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi{
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (--test_globals.io_loop_ref == 0)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi io_loop_stop(current_ioloop);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi}
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomivoid test_program_client_destroy(struct test_client **_client)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi{
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct test_client *client = *_client;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi *_client = NULL;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
ad9afb64630511d5e25bc5bc11c5304986156928Timo Sirainen if (o_stream_finish(client->out) < 0)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi i_error("output error: %s", o_stream_get_error(client->out));
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&client->io);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi o_stream_unref(&client->out);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi i_stream_unref(&client->in);
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek o_stream_unref(&client->os_body);
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek i_stream_unref(&client->body);
c31803dcbdf3d4e3b836134a2a04ee2cd5251ce5Aki Tuomi i_close_fd(&client->fd);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi pool_unref(&client->pool);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_globals.client = NULL;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_io_loop_stop();
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi}
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomiint test_program_input_handle(struct test_client *client, const char *line)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi{
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi int cmp = -1;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi const char *arg;
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi struct istream *is;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi switch(client->state) {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi case CLIENT_STATE_INIT:
fba2690b7b40d123ecc7271d041b1571358d177dStephan Bosch test_assert((cmp = strncmp(line, "VERSION\tscript\t", 15)) == 0);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (cmp == 0) {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi client->state = CLIENT_STATE_VERSION;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi } else
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi return -1;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi break;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi case CLIENT_STATE_VERSION:
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (strcmp(line, "noreply") == 0 ||
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi strcmp(line, "-") == 0)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi cmp = 0;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_assert(cmp == 0);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (cmp == 0)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi client->state = CLIENT_STATE_ARGS;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi else
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi return -1;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi break;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi case CLIENT_STATE_ARGS:
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (strcmp(line, "") == 0) {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi array_append_zero(&client->args);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi client->state = CLIENT_STATE_BODY;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi return 0;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi }
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi arg = p_strdup(client->pool, line);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi array_append(&client->args, &arg, 1);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi break;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi case CLIENT_STATE_BODY:
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi client->os_body =
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi iostream_temp_create_named(".dovecot.test.", 0,
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi "test_program_input body");
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi is = client->in;
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi client->in = i_stream_create_dot(is, FALSE);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi i_stream_unref(&is);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi switch(o_stream_send_istream(client->os_body, client->in)) {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi return -1;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi break;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi client->body = iostream_temp_finish(&client->os_body,
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi -1);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi return 1;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi i_panic("Cannot write to ostream-temp");
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi }
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi break;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi }
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi return 0;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi}
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomivoid test_program_run(struct test_client *client)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi{
870bf394d43e653dd7669093a12bafbfc0b8fe92Timo Sirainen const char *const *args;
870bf394d43e653dd7669093a12bafbfc0b8fe92Timo Sirainen unsigned int count;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi struct ostream *os;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi timeout_remove(&test_globals.to);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi test_assert(array_is_created(&client->args));
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi if (array_is_created(&client->args)) {
870bf394d43e653dd7669093a12bafbfc0b8fe92Timo Sirainen args = array_get(&client->args, &count);
870bf394d43e653dd7669093a12bafbfc0b8fe92Timo Sirainen test_assert(count > 0);
870bf394d43e653dd7669093a12bafbfc0b8fe92Timo Sirainen if (count > 0) {
870bf394d43e653dd7669093a12bafbfc0b8fe92Timo Sirainen if (strcmp(args[0], "test_program_success")==0) {
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi /* return hello world */
870bf394d43e653dd7669093a12bafbfc0b8fe92Timo Sirainen i_assert(count >= 3);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi o_stream_nsend_str(client->out, t_strdup_printf(
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi "%s %s\r\n.\n+\n",
870bf394d43e653dd7669093a12bafbfc0b8fe92Timo Sirainen args[1], args[2]));
870bf394d43e653dd7669093a12bafbfc0b8fe92Timo Sirainen } else if (strcmp(args[0], "test_program_io")==0) {
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi os = o_stream_create_dot(client->out, FALSE);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi o_stream_send_istream(os, client->body);
a2583397219ebbb877fcf84107f0ca7f56362760Timo Sirainen test_assert(o_stream_finish(os) > 0);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi o_stream_unref(&os);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi o_stream_nsend_str(client->out, "+\n");
870bf394d43e653dd7669093a12bafbfc0b8fe92Timo Sirainen } else if (strcmp(args[0], "test_program_failure")==0) {
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi o_stream_nsend_str(client->out, ".\n-\n");
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi }
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi } else
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi o_stream_nsend_str(client->out, ".\n-\n");
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi }
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi test_program_client_destroy(&client);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi}
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomivoid test_program_input(struct test_client *client)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi{
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi const char *line = "";
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi int ret = 0;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (client->state == CLIENT_STATE_BODY) {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (test_program_input_handle(client, NULL)==0 &&
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi !client->in->eof)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi return;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi } else {
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi while((line = i_stream_read_next_line(client->in)) != NULL) {
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi ret = test_program_input_handle(client, line);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi if (client->state == CLIENT_STATE_BODY)
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi ret = test_program_input_handle(client, NULL);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi if (ret != 0) break;
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi }
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if ((line == NULL && !client->in->eof) ||
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi (line != NULL &&
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi ret == 0))
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi return;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi }
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi /* incur short delay to make sure the client did not disconnect
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi prematurely */
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi io_remove(&client->io);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_globals.to = timeout_add_short(100, test_program_run, client);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (client->state != CLIENT_STATE_BODY) {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (client->in->eof)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi i_warning("Client prematurely disconnected");
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi else
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi i_warning("Client sent invalid line: %s", line);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi }
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi}
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomivoid test_program_connected(struct test_server *server)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi{
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi int fd;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi i_assert(server->client == NULL);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi fd = net_accept(server->listen_fd, NULL, NULL); /* makes no sense on net */
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (fd < 0)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi i_fatal("Failed to accept connection: %m");
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi pool_t pool = pool_alloconly_create("test_program client", 1024);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct test_client *client = p_new(pool, struct test_client, 1);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi client->pool = pool;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi client->fd = fd;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi client->in = i_stream_create_fd(fd, -1);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi client->out = o_stream_create_fd(fd, -1);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi client->io = io_add_istream(client->in, test_program_input, client);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi p_array_init(&client->args, client->pool, 2);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi server->client = client;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_io_loop_run();
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi}
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomivoid test_program_setup(void) {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_begin("test_program_setup");
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_globals.ioloop = io_loop_create();
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi io_loop_set_current(test_globals.ioloop);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi /* create listener */
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct ip_addr ip;
a89fc6c5055c364e8bed8d2c1492e68bc37c7fdeTimo Sirainen test_globals.port = 0;
24c5bcb933f82becfb24aa5bd76f040cca2eca3fAki Tuomi test_assert(net_addr2ip("127.0.0.1", &ip) == 0);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_globals.listen_fd = net_listen(&ip, &test_globals.port, 1);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (test_globals.listen_fd < 0)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi i_fatal("Cannot create TCP listener: %m");
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_globals.io = io_add(test_globals.listen_fd, IO_READ,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_connected, &test_globals);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_end();
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi}
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomivoid test_program_teardown(void)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi{
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_begin("test_program_teardown");
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (test_globals.client != NULL)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_client_destroy(&test_globals.client);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi io_remove(&test_globals.io);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi i_close_fd(&test_globals.listen_fd);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi io_loop_destroy(&test_globals.ioloop);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_end();
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi}
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomivoid test_program_async_callback(int result, int *ret)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi{
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi *ret = result;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_io_loop_stop();
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi}
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomivoid test_program_success(void) {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_begin("test_program_success");
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi int ret = -2;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi const char *const args[] = {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi "test_program_success", "hello", "world", NULL
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi };
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct program_client *pc =
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi program_client_net_create("127.0.0.1", test_globals.port, args,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi &pc_set, FALSE);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi buffer_t *output = buffer_create_dynamic(default_pool, 16);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct ostream *os = test_ostream_create(output);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_set_output(pc, os);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_run_async(pc, test_program_async_callback, &ret);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (ret == -2)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_io_loop_run();
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_assert(ret == 1);
a371ea8bd48d45548cd7aa16d4f5aeb38ba48c91Aki Tuomi test_assert(strcmp(str_c(output), "hello world") == 0);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_destroy(&pc);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi o_stream_unref(&os);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi buffer_free(&output);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi i_assert(test_globals.client == NULL);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_end();
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi}
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomivoid test_program_io(void) {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_begin("test_program_io (async)");
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi int ret = -2;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi const char *const args[] = {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi "test_program_io", NULL
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi };
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct program_client *pc =
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_net_create("127.0.0.1", test_globals.port, args,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi &pc_set, FALSE);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct istream *is = test_istream_create(pclient_test_io_string);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_set_input(pc, is);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi buffer_t *output = buffer_create_dynamic(default_pool, 16);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct ostream *os = test_ostream_create(output);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_set_output(pc, os);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_run_async(pc, test_program_async_callback, &ret);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (ret == -2)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_io_loop_run();
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_assert(ret == 1);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_assert(strcmp(str_c(output), pclient_test_io_string) == 0);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_destroy(&pc);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi i_stream_unref(&is);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi o_stream_unref(&os);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi buffer_free(&output);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi i_assert(test_globals.client == NULL);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_end();
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi}
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomivoid test_program_failure(void) {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_begin("test_program_failure");
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi int ret = -2;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi const char *const args[] = {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi "test_program_failure", NULL
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi };
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct program_client *pc =
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_net_create("127.0.0.1", test_globals.port, args,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi &pc_set, FALSE);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi buffer_t *output = buffer_create_dynamic(default_pool, 16);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct ostream *os = test_ostream_create(output);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_set_output(pc, os);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_run_async(pc, test_program_async_callback, &ret);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (ret == -2)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_io_loop_run();
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_assert(ret == 0);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_destroy(&pc);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi o_stream_unref(&os);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi buffer_free(&output);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi i_assert(test_globals.client == NULL);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_end();
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi}
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomivoid test_program_noreply(void) {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_begin("test_program_noreply");
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi int ret = -2;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi const char *const args[] = {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi "test_program_success", "hello", "world", NULL
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi };
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct program_client *pc =
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_net_create("127.0.0.1", test_globals.port, args,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi &pc_set, TRUE);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_run_async(pc, test_program_async_callback, &ret);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (ret == -2)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_io_loop_run();
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_assert(ret == 1);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_destroy(&pc);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi i_assert(test_globals.client == NULL);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_end();
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi}
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomistatic
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomivoid test_program_refused(void) {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_begin("test_program_refused");
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi int ret = -2;
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi const char *const args[] = {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi "test_program_success", "hello", "world", NULL
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi };
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct ip_addr ips[4];
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (net_addr2ip("::1", &ips[0]) < 0 ||
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi net_addr2ip("127.0.0.3", &ips[1]) < 0 ||
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi net_addr2ip("127.0.0.2", &ips[2]) < 0 ||
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi net_addr2ip("127.0.0.1", &ips[3]) < 0) {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi i_fatal("Cannot convert addresses");
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi }
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi struct program_client *pc =
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_net_create_ips(ips, N_ELEMENTS(ips),
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_globals.port, args,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi &pc_set, TRUE);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_expect_errors(N_ELEMENTS(ips)-1);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_run_async(pc, test_program_async_callback, &ret);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi if (ret == -2)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_io_loop_run();
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_assert(ret == 1);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi program_client_destroy(&pc);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_end();
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi}
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomiint main(void)
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi{
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi void (*tests[])(void) = {
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_setup,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_success,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_io,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_failure,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_noreply,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_refused,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi test_program_teardown,
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi NULL
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi };
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi return test_run(tests);
3f67fea2e5a12390d280315c37c80302a9dab683Aki Tuomi}