test-program-client-unix.c revision 4755f8d37a2abb18f3783b4102c26fcd11a9f379
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi/* Copyright (c) 2002-2016 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
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomistatic const char *TEST_SOCKET = "/tmp/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,
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi .input_idle_timeout_secs = 5000,
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi .gid = -1,
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi .uid = -1,
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
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi if (o_stream_nfinish(client->out) != 0)
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi i_error("output error: %s", o_stream_get_error(client->out));
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi io_remove(&client->io);
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi o_stream_unref(&client->out);
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi i_stream_unref(&client->in);
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi if (client->os_body != NULL)
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi o_stream_unref(&client->os_body);
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi if (client->body != NULL)
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi i_stream_unref(&client->body);
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi close(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:
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi test_assert((cmp = strcmp(line, "VERSION\tscript\t3\t0")) == 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:
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi client->os_body = iostream_temp_create_named("/tmp", 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:
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
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{
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi const char *arg;
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi test_assert(array_count(&client->args) > 0);
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi arg = *array_idx(&client->args, 0);
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi if (strcmp(arg, "test_program_success")==0) {
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi /* return hello world */
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi o_stream_nsend_str(client->out, t_strdup_printf("%s %s\n+\n",
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi *array_idx(&client->args, 1),
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi *array_idx(&client->args, 2)));
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi } else if (strcmp(arg, "test_program_io")==0) {
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi o_stream_send_istream(client->out, client->body);
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi o_stream_nsend_str(client->out, "+\n");
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi } else if (strcmp(arg, "test_program_failure")==0) {
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi o_stream_nsend_str(client->out, "-\n");
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi }
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi}
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomistatic
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomivoid test_program_input(struct test_client *client)
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi{
4755f8d37a2abb18f3783b4102c26fcd11a9f379Timo Sirainen const char *line = "";
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi if (client->state == CLIENT_STATE_BODY) {
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi if (test_program_input_handle(client, NULL)==0 && !client->in->eof) return;
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi } else {
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi line = i_stream_read_next_line(client->in);
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi if ((line == NULL && !client->in->eof) ||
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi (line != NULL && test_program_input_handle(client, line) == 0))
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi return;
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi }
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi if (client->in->eof)
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi test_program_run(client);
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi if (client->state != CLIENT_STATE_BODY) {
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi if (client->in->eof)
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi i_warning("Client prematurely disconnected");
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi else
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi i_warning("Client sent invalid line: %s", line);
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi }
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi test_program_client_destroy(&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);
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi close(test_globals.listen_fd);
0a017e924aa2490f6a54096d11e534b2a7554ebeAki Tuomi io_loop_destroy(&test_globals.ioloop);
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}