Skip to content

Commit

Permalink
lib-smtp: test-smtp-client-errors: Add tests for transaction timeouts.
Browse files Browse the repository at this point in the history
  • Loading branch information
stephanbosch authored and villesavolainen committed Feb 6, 2019
1 parent 9bdd126 commit baa5f18
Showing 1 changed file with 263 additions and 0 deletions.
263 changes: 263 additions & 0 deletions src/lib-smtp/test-smtp-client-errors.c
Expand Up @@ -2531,6 +2531,268 @@ static void test_authentication_failed(void)
test_end();
}

/*
* Transaction timeout
*/

/* server */

static int
test_transaction_timeout_input_line(struct server_connection *conn,
const char *line ATTR_UNUSED)
{
switch (conn->state) {
case SERVER_CONNECTION_STATE_EHLO:
break;
case SERVER_CONNECTION_STATE_MAIL_FROM:
if (server_index == 0)
sleep(20);
break;
case SERVER_CONNECTION_STATE_RCPT_TO:
if (server_index == 1)
sleep(20);
break;
case SERVER_CONNECTION_STATE_DATA:
if (server_index == 2)
sleep(20);
break;
case SERVER_CONNECTION_STATE_FINISH:
break;
}
return 0;
}

static void test_server_transaction_timeout(unsigned int index)
{
test_server_input_line = test_transaction_timeout_input_line;
test_server_run(index);
}

/* client */

struct _transaction_timeout {
unsigned int count;
};

struct _transaction_timeout_peer {
struct _transaction_timeout *context;
unsigned int index;

struct smtp_client_connection *conn;
struct smtp_client_transaction *trans;
struct timeout *to;

bool login_callback:1;
bool mail_from_callback:1;
bool rcpt_to_callback:1;
bool rcpt_data_callback:1;
bool data_callback:1;
};

static void
test_client_transaction_timeout_mail_from_cb(const struct smtp_reply *reply,
struct _transaction_timeout_peer *pctx)
{
if (debug)
i_debug("MAIL FROM REPLY[%u]: %s", pctx->index, smtp_reply_log(reply));

pctx->mail_from_callback = TRUE;

switch (pctx->index) {
case 0:
test_assert(reply->status == 451);
break;
case 1: case 2: case 3:
test_assert(smtp_reply_is_success(reply));
break;
}
}

static void
test_client_transaction_timeout_rcpt_to_cb(const struct smtp_reply *reply,
struct _transaction_timeout_peer *pctx)
{
if (debug)
i_debug("RCPT TO REPLY[%u]: %s", pctx->index, smtp_reply_log(reply));

pctx->rcpt_to_callback = TRUE;

switch (pctx->index) {
case 0: case 1:
test_assert(reply->status == 451);
break;
case 2: case 3:
test_assert(smtp_reply_is_success(reply));
break;
}
}

static void
test_client_transaction_timeout_rcpt_data_cb(const struct smtp_reply *reply,
struct _transaction_timeout_peer *pctx)
{
if (debug)
i_debug("RCPT DATA REPLY[%u]: %s", pctx->index, smtp_reply_log(reply));

pctx->rcpt_data_callback = TRUE;

switch (pctx->index) {
case 0: case 1:
i_unreached();
case 2:
test_assert(reply->status == 451);
break;
case 3:
test_assert(smtp_reply_is_success(reply));
break;
}
}

static void
test_client_transaction_timeout_data_cb(const struct smtp_reply *reply,
struct _transaction_timeout_peer *pctx)
{
if (debug)
i_debug("DATA REPLY[%u]: %s", pctx->index, smtp_reply_log(reply));

pctx->data_callback = TRUE;

switch (pctx->index) {
case 0: case 1: case 2:
test_assert(reply->status == 451);
break;
case 3:
test_assert(smtp_reply_is_success(reply));
break;
}
}

static void
test_client_transaction_timeout_finished(struct _transaction_timeout_peer *pctx)
{
struct _transaction_timeout *ctx = pctx->context;

if (debug)
i_debug("FINISHED[%u]", pctx->index);
if (--ctx->count == 0) {
i_free(ctx);
io_loop_stop(ioloop);
}

switch (pctx->index) {
case 0: case 1:
test_assert(pctx->mail_from_callback);
test_assert(pctx->rcpt_to_callback);
test_assert(!pctx->rcpt_data_callback);
test_assert(pctx->data_callback);
break;
case 2: case 3:
test_assert(pctx->mail_from_callback);
test_assert(pctx->rcpt_to_callback);
test_assert(pctx->rcpt_data_callback);
test_assert(pctx->data_callback);
break;
}

pctx->trans = NULL;
timeout_remove(&pctx->to);
i_free(pctx);
}

static void
test_client_transaction_timeout_submit2(struct _transaction_timeout_peer *pctx)
{
struct smtp_client_transaction *strans = pctx->trans;
static const char *message =
"From: stephan@example.com\r\n"
"To: timo@example.com\r\n"
"Subject: Frop!\r\n"
"\r\n"
"Frop!\r\n";
struct istream *input;

timeout_remove(&pctx->to);

input = i_stream_create_from_data(message, strlen(message));
i_stream_set_name(input, "message");

smtp_client_transaction_send
(strans, input, test_client_transaction_timeout_data_cb, pctx);
i_stream_unref(&input);
}

static void
test_client_transaction_timeout_submit1(struct _transaction_timeout_peer *pctx)
{
timeout_remove(&pctx->to);

smtp_client_transaction_add_rcpt(pctx->trans,
SMTP_ADDRESS_LITERAL("rcpt", "example.com"), NULL,
test_client_transaction_timeout_rcpt_to_cb,
test_client_transaction_timeout_rcpt_data_cb, pctx);

pctx->to = timeout_add_short(500,
test_client_transaction_timeout_submit2, pctx);
}

static void
test_client_transaction_timeout_submit(struct _transaction_timeout *ctx,
unsigned int index)
{
struct _transaction_timeout_peer *pctx;

pctx = i_new(struct _transaction_timeout_peer, 1);
pctx->context = ctx;
pctx->index = index;

pctx->conn = smtp_client_connection_create(smtp_client,
SMTP_PROTOCOL_SMTP, net_ip2addr(&bind_ip), bind_ports[index],
SMTP_CLIENT_SSL_MODE_NONE, NULL);
pctx->trans = smtp_client_transaction_create(pctx->conn,
SMTP_ADDRESS_LITERAL("sender", "example.com"), NULL,
test_client_transaction_timeout_finished, pctx);
smtp_client_transaction_set_timeout(pctx->trans, 1000);
smtp_client_transaction_start(pctx->trans,
test_client_transaction_timeout_mail_from_cb, pctx);
smtp_client_connection_unref(&pctx->conn);

pctx->to = timeout_add_short(500,
test_client_transaction_timeout_submit1, pctx);
}

static bool
test_client_transaction_timeout(
const struct smtp_client_settings *client_set)
{
struct _transaction_timeout *ctx;
unsigned int i;

ctx = i_new(struct _transaction_timeout, 1);
ctx->count = 4;

smtp_client = smtp_client_init(client_set);

for (i = 0; i < ctx->count; i++)
test_client_transaction_timeout_submit(ctx, i);

return TRUE;
}

/* test */

static void test_transaction_timeout(void)
{
struct smtp_client_settings smtp_client_set;

test_client_defaults(&smtp_client_set);

test_begin("transaction timeout");
test_run_client_server(&smtp_client_set,
test_client_transaction_timeout,
test_server_transaction_timeout, 6, NULL);
test_end();
}

/*
* All tests
*/
Expand All @@ -2555,6 +2817,7 @@ static void (*const test_functions[])(void) = {
test_dns_timeout,
test_dns_lookup_failure,
test_authentication_failed,
test_transaction_timeout,
NULL
};

Expand Down

0 comments on commit baa5f18

Please sign in to comment.