/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "lib-signals.h"
#include "str.h"
#include "hostpid.h"
#include "ioloop.h"
#include "istream.h"
#include "istream-chain.h"
#include "ostream.h"
#include "time-util.h"
#include "unlink-directory.h"
#include "write-full.h"
#include "connection.h"
#include "master-service.h"
#include "istream-dot.h"
#include "test-common.h"
#include "smtp-address.h"
#include "smtp-submit.h"
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
static const char *test_message1 =
"Subject: Test message\r\n"
"To: rcpt@example.com\r\n"
"From: sender@example.com\r\n"
"\r\n"
"Test message\r\n";
static const char *test_message2 =
"Subject: Test message\r\n"
"To: rcpt@example.com\r\n"
"From: sender@example.com\r\n"
"\r\n"
"Test message Test message Test message Test message Test message\r\n"
"Test message Test message Test message Test message Test message\r\n"
"Test message Test message Test message Test message Test message\r\n"
"Test message Test message Test message Test message Test message\r\n"
"Test message Test message Test message Test message Test message\r\n"
"Test message Test message Test message Test message Test message\r\n";
/*
* Types
*/
struct server_connection {
void *context;
};
typedef bool (*test_client_init_t)
(const struct smtp_submit_settings *submit_set);
/*
* State
*/
/* common */
/* server */
static unsigned int server_pids_count = 0;
static unsigned int server_index;
/* client */
/*
* Forward declarations
*/
/* server */
static void test_server_run(unsigned int index);
static void
/* client */
static void
static void test_client_deinit(void);
static int
const char **error_r);
static int
const char **error_r);
/* test*/
static const char *test_tmp_dir_get(void);
static void
static void test_run_client_server(
const struct smtp_submit_settings *submit_set,
unsigned int server_tests_count)
ATTR_NULL(3);
/*
* Host lookup failed
*/
/* client */
static bool
{
int ret;
return FALSE;
}
/* test */
static void test_host_lookup_failed(void)
{
test_begin("host lookup failed");
NULL, 0);
test_end();
}
/*
* Connection refused
*/
/* server */
static void
{
}
/* client */
static bool
{
int ret;
return FALSE;
}
/* test */
static void test_connection_refused(void)
{
test_begin("connection refused");
test_end();
}
/*
* Connection timed out
*/
/* server */
static void
{
sleep(10);
}
{
}
/* client */
static bool
{
int ret;
time = ioloop_time;
return FALSE;
}
/* test */
static void test_connection_timed_out(void)
{
test_begin("connection timed out");
test_end();
}
/*
* Bad greeting
*/
/* server */
static void
{
}
static void
{
"554 No SMTP service here.\r\n");
}
{
}
/* client */
static bool
{
int ret;
return FALSE;
}
/* test */
static void test_bad_greeting(void)
{
test_begin("bad greeting");
test_end();
}
/*
* Denied HELO
*/
/* server */
static void
{
const char *line;
return;
}
"550 Command rejected for testing reasons\r\n");
}
static void
{
}
{
}
/* client */
static bool
{
int ret;
return FALSE;
}
/* test */
static void test_denied_helo(void)
{
test_begin("denied helo");
test_end();
}
/*
* Disconnect HELO
*/
/* server */
static void
{
const char *line;
return;
}
}
static void
{
}
{
}
/* client */
static bool
{
int ret;
return FALSE;
}
/* test */
static void test_disconnect_helo(void)
{
test_begin("disconnect helo");
test_end();
}
/*
* Denied MAIL
*/
/* server */
enum _denied_mail_state {
};
struct _denied_mail_server {
};
static void
{
const char *line;
} else {
}
for (;;) {
return;
}
case DENIED_MAIL_STATE_EHLO:
"250-testserver\r\n"
"250-PIPELINING\r\n"
"250-ENHANCEDSTATUSCODES\r\n"
"250-8BITMIME\r\n"
"250 DSN\r\n");
return;
"453 4.3.2 Incapable of accepting messages at this time.\r\n");
return;
}
i_unreached();
}
}
static void
{
}
{
}
/* client */
static bool
{
int ret;
return FALSE;
}
/* test */
static void test_denied_mail(void)
{
test_begin("denied mail");
test_end();
}
/*
* Denied RCPT
*/
/* server */
enum _denied_rcpt_state {
};
struct _denied_rcpt_server {
};
static void
{
const char *line;
} else {
}
for (;;) {
return;
}
case DENIED_RCPT_STATE_EHLO:
"250-testserver\r\n"
"250-PIPELINING\r\n"
"250-ENHANCEDSTATUSCODES\r\n"
"250-8BITMIME\r\n"
"250 DSN\r\n");
return;
"250 2.1.0 Ok\r\n");
continue;
"550 5.4.3 Directory server failure\r\n");
return;
}
i_unreached();
}
}
static void
{
}
{
}
/* client */
static bool
{
int ret;
return FALSE;
}
/* test */
static void test_denied_rcpt(void)
{
test_begin("denied rcpt");
test_end();
}
/*
* Denied second RCPT
*/
/* server */
enum _denied_second_rcpt_state {
};
struct _denied_second_rcpt_server {
};
static void
{
const char *line;
} else {
}
for (;;) {
return;
}
"250-testserver\r\n"
"250-PIPELINING\r\n"
"250-ENHANCEDSTATUSCODES\r\n"
"250-8BITMIME\r\n"
"250 DSN\r\n");
return;
"250 2.1.0 Ok\r\n");
continue;
"250 2.1.5 Ok\r\n");
continue;
"550 5.4.3 Directory server failure\r\n");
return;
}
i_unreached();
}
}
static void
{
}
{
}
/* client */
static bool
{
int ret;
return FALSE;
}
/* test */
static void test_denied_second_rcpt(void)
{
test_begin("denied second rcpt");
test_end();
}
/*
* Denied DATA
*/
/* server */
enum _denied_data_state {
};
struct _denied_data_server {
};
static void
{
const char *line;
} else {
}
for (;;) {
return;
}
case DENIED_DATA_STATE_EHLO:
"250-testserver\r\n"
"250-PIPELINING\r\n"
"250-ENHANCEDSTATUSCODES\r\n"
"250-8BITMIME\r\n"
"250 DSN\r\n");
return;
"250 2.1.0 Ok\r\n");
continue;
"250 2.1.5 Ok\r\n");
continue;
case DENIED_DATA_STATE_DATA:
"500 5.0.0 Unacceptabe recipients\r\n");
return;
}
i_unreached();
}
}
static void
{
}
{
}
/* client */
static bool
{
int ret;
return FALSE;
}
/* test */
static void test_denied_data(void)
{
test_begin("denied data");
test_end();
}
/*
* Data failure
*/
/* server */
enum _data_failure_state {
};
struct _data_failure_server {
};
static void
{
const char *line;
} else {
}
for (;;) {
return;
}
case DATA_FAILURE_STATE_EHLO:
"250-testserver\r\n"
"250-PIPELINING\r\n"
"250-ENHANCEDSTATUSCODES\r\n"
"250-8BITMIME\r\n"
"250 DSN\r\n");
return;
"250 2.1.0 Ok\r\n");
continue;
"250 2.1.5 Ok\r\n");
continue;
case DATA_FAILURE_STATE_DATA:
"354 End data with <CR><LF>.<CR><LF>\r\n");
continue;
"552 5.2.3 Message length exceeds administrative limit\r\n");
return;
}
continue;
}
i_unreached();
}
}
static void
{
}
{
}
/* client */
static bool
{
int ret;
return FALSE;
}
/* test */
static void test_data_failure(void)
{
test_begin("data failure");
test_end();
}
/*
* Data disconnect
*/
/* server */
enum _data_disconnect_state {
};
struct _data_disconnect_server {
};
static void
{
const char *line;
} else {
}
for (;;) {
return;
}
"250-testserver\r\n"
"250-PIPELINING\r\n"
"250-ENHANCEDSTATUSCODES\r\n"
"250-8BITMIME\r\n"
"250 DSN\r\n");
return;
"250 2.1.0 Ok\r\n");
continue;
"250 2.1.5 Ok\r\n");
continue;
"354 End data with <CR><LF>.<CR><LF>\r\n");
continue;
return;
}
i_unreached();
}
}
static void
{
}
{
}
/* client */
static bool
{
int ret;
return FALSE;
}
/* test */
static void test_data_disconnect(void)
{
test_begin("data disconnect");
test_end();
}
/*
* Data timout
*/
/* server */
enum _data_timout_state {
};
struct _data_timout_server {
};
static void
{
const char *line;
} else {
}
for (;;) {
return;
}
case DATA_TIMEOUT_STATE_EHLO:
"250-testserver\r\n"
"250-PIPELINING\r\n"
"250-ENHANCEDSTATUSCODES\r\n"
"250-8BITMIME\r\n"
"250 DSN\r\n");
return;
"250 2.1.0 Ok\r\n");
continue;
"250 2.1.5 Ok\r\n");
continue;
case DATA_TIMEOUT_STATE_DATA:
"354 End data with <CR><LF>.<CR><LF>\r\n");
continue;
sleep(10);
return;
}
i_unreached();
}
}
static void
{
}
{
}
/* client */
static bool
{
int ret;
time = ioloop_time;
return FALSE;
}
/* test */
static void test_data_timeout(void)
{
test_begin("data timeout");
test_end();
}
/*
* Successful delivery
*/
/* server */
enum _successful_delivery_state {
};
struct _successful_delivery_server {
char *file_path;
};
static void
{
const char *line;
} else {
}
// FIXME: take structure from test-smtp-client-errors
for (;;) {
int fd;
i_fatal("failed create tmp file for message: "
}
}
switch (res) {
break;
return;
i_error("test server: "
return;
i_error("test server: "
return;
}
"250 2.0.0 Ok: queued as 73BDE342129\r\n");
continue;
}
return;
}
"250-testserver\r\n"
"250-PIPELINING\r\n"
"250-ENHANCEDSTATUSCODES\r\n"
"250-8BITMIME\r\n"
"250 DSN\r\n");
return;
"250 2.1.0 Ok\r\n");
continue;
"250 2.1.5 Ok\r\n");
continue;
"354 End data with <CR><LF>.<CR><LF>\r\n");
continue;
break;
}
i_unreached();
}
}
static void
{
}
static void
{
}
{
}
/* client */
static bool
{
int ret;
/* send the message */
/* verify delivery */
t_strdup_printf("%s/message-%u.eml",
test_tmp_dir_get(), bind_ports[0]));
return FALSE;
}
struct _parallel_delivery_client {
unsigned int count;
};
static void
struct _parallel_delivery_client *ctx)
{
}
static bool
{
ioloop = io_loop_create();
/* submit 1 */
/* submit 2 */
/* verify delivery */
t_strdup_printf("%s/message-%u.eml",
test_tmp_dir_get(), bind_ports[0]));
t_strdup_printf("%s/message-%u.eml",
return FALSE;
}
/* test */
static void test_successful_delivery(void)
{
test_begin("successful delivery");
test_end();
test_begin("parallel delivery");
test_end();
}
/*
* Failed sendmail
*/
/* client */
static bool
{
int ret;
return FALSE;
}
/* test */
static void test_failed_sendmail(void)
{
test_begin("failed sendmail");
test_end();
}
/*
* Successful sendmail
*/
/* client */
static bool
{
int ret;
/* verify delivery */
return FALSE;
}
/* test */
static void test_successful_sendmail(void)
{
test_begin("successful sendmail");
test_end();
}
/*
* Parallel sendmail
*/
/* client */
struct _parallel_sendmail_client {
unsigned int count;
};
static void
struct _parallel_sendmail_client *ctx)
{
}
static bool
{
ioloop = io_loop_create();
/* submit 1 */
/* submit 2 */
/* verify delivery */
return FALSE;
}
/* test */
static void test_parallel_sendmail(void)
{
test_begin("parallel sendmail");
test_end();
}
/*
* All tests
*/
static void (*const test_functions[])(void) = {
};
/*
* Test client
*/
static void
{
}
static void test_client_deinit(void)
{
}
static int
const char **error_r)
{
int ret;
/* send the message */
return ret;
}
static int
const struct smtp_submit_settings *smtp_set,
const char **error_r)
{
return test_client_smtp_send_simple(smtp_set,
}
/*
* Test server
*/
/* client connection */
static void
{
}
static void
{
if (test_server_init != NULL)
}
static void
{
if (test_server_deinit != NULL)
}
static void
{
(struct server_connection *)_conn;
}
static void
{
int fd;
/* accept new client */
if (fd == -1)
return;
if (fd == -2) {
i_fatal("test server: accept() failed: %m");
}
}
/* */
};
};
{
/* open server socket */
/* close server socket */
}
/*
* Tests
*/
{
if (debug)
if (fd == -1) {
i_fatal("listen(%s:%u) failed: %m",
}
return fd;
}
static void test_servers_kill_all(void)
{
unsigned int i;
if (server_pids_count > 0) {
for (i = 0; i < server_pids_count; i++) {
server_pids[i] = -1;
}
}
}
server_pids_count = 0;
}
static void test_tmp_dir_init(void)
{
("/tmp/dovecot-test-smtp-client.%s.%s",
}
static const char *test_tmp_dir_get(void)
{
i_fatal("failed to create temporary directory `%s': %m",
tmp_dir);
}
return tmp_dir;
}
static void test_tmp_dir_deinit(void)
{
const char *error;
if (unlink_directory(tmp_dir,
UNLINK_DIRECTORY_FLAG_RMDIR, &error) < 0) {
i_warning("failed to remove temporary directory `%s': %s.",
}
}
static void
{
const unsigned char *data;
int ret;
const unsigned char *mdata;
if (test_has_failed())
break;
if (test_has_failed())
break;
}
input->stream_errno == 0 &&
}
static void test_run_client_server(
const struct smtp_submit_settings *submit_set,
unsigned int server_tests_count)
{
unsigned int i;
server_pids = NULL;
server_pids_count = 0;
if (server_tests_count > 0) {
for (i = 0; i < server_tests_count; i++)
for (i = 0; i < server_tests_count; i++)
for (i = 0; i < server_tests_count; i++) {
server_port = bind_ports[i];
i_fatal("fork() failed: %m");
if (server_pids[i] == 0) {
server_pids_count = 0;
hostpid_init();
while (current_ioloop != NULL) {
}
if (debug)
/* child: server */
ioloop = io_loop_create();
server_test(i);
if (fd_listen != -1)
/* wait for it to be killed; this way, valgrind will not
object to this process going away inelegantly. */
sleep(60);
exit(1);
}
if (fd_listen != -1)
}
if (debug)
}
/* parent: client */
server_port = 0;
ioloop = io_loop_create();
if (client_test(submit_set))
}
/*
* Main
*/
static void
{
if (terminating != 0)
terminating = 1;
/* make sure we don't leave any pesky children alive */
}
static void test_atexit(void)
{
}
{
int c;
while ((c = master_getopt(master_service)) > 0) {
switch (c) {
case 'D':
break;
default:
}
}
/* listen on localhost */
}