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