Skip to content
Snippets Groups Projects
testsuite.c 7.11 KiB
/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
 */

#include "lib.h"
#include "lib-signals.h"
#include "ioloop.h"
#include "env-util.h"
#include "ostream.h"
#include "hostpid.h"
#include "mail-storage.h"
#include "mail-namespace.h"
#include "master-service.h"
#include "master-service-settings.h"
#include "mail-storage-service.h"

#include "sieve.h"
#include "sieve-extensions.h"
#include "sieve-script.h"
#include "sieve-binary.h"
#include "sieve-result.h"
#include "sieve-interpreter.h"

#include "mail-raw.h"
#include "sieve-tool.h"

#include "testsuite-common.h"
#include "testsuite-settings.h"
#include "testsuite-result.h"
#include "testsuite-message.h"
#include "testsuite-smtp.h"
#include "testsuite-mailstore.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <pwd.h>
#include <sysexits.h>

const struct sieve_script_env *testsuite_scriptenv;

/*
 * Configuration
 */

#define DEFAULT_SENDMAIL_PATH "/usr/lib/sendmail"
#define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON"

/*
 * Testsuite initialization 
 */

static const struct sieve_environment testsuite_sieve_env = {
	sieve_tool_get_homedir,
	testsuite_setting_get
};

static void testsuite_tool_init(const char *extensions) 
{
	testsuite_settings_init();

	sieve_tool_init(&testsuite_sieve_env, FALSE);

	sieve_extensions_set_string(sieve_instance, extensions);

	testsuite_init(sieve_instance);
}

static void testsuite_tool_deinit(void)
{
	testsuite_deinit();
	
	sieve_tool_deinit();

	testsuite_settings_deinit();
}

/*
 * Testsuite execution
 */

static void print_help(void)
{
	printf(
"Usage: testsuite [-d <dump filename>] <scriptfile>\n"
	);
}

static int testsuite_run
(struct sieve_binary *sbin, const struct sieve_message_data *msgdata, 
	const struct sieve_script_env *senv, struct sieve_error_handler *ehandler)
{
	struct sieve_interpreter *interp;
	struct sieve_result *result;
	int ret = 0;

	/* Create the interpreter */
	if ( (interp=sieve_interpreter_create(sbin, ehandler)) == NULL )
		return SIEVE_EXEC_BIN_CORRUPT;

	/* Reset execution status */
	if ( senv->exec_status != NULL )
		memset(senv->exec_status, 0, sizeof(*senv->exec_status));

	/* Run the interpreter */
	result = testsuite_result_get();
	sieve_result_ref(result);
	ret = sieve_interpreter_run(interp, msgdata, senv, result);
	sieve_result_unref(&result);

	/* Free the interpreter */
	sieve_interpreter_free(&interp);

	return ret;
}

/* IEW.. YUCK.. and so forth.. */
static const char *_get_cwd(void)
{
	static char cwd[PATH_MAX];
	const char *result;

	result = t_strdup(getcwd(cwd, sizeof(cwd)));

	return result;
}

int main(int argc, char **argv) 
{
	enum mail_storage_service_flags service_flags = 0;
	struct mail_storage_service_ctx *storage_service;
	struct mail_storage_service_user *service_user;
	struct mail_storage_service_input service_input;
	struct mail_user *mail_user_dovecot;
	const char *scriptfile, *dumpfile, *extensions; 
	const char *user, *home, *errstr;
	struct sieve_binary *sbin;
	const char *sieve_dir;
	bool trace = FALSE;
	int ret, c;

	master_service = master_service_init
		("testsuite", MASTER_SERVICE_FLAG_STANDALONE, &argc, &argv, "d:x:t");

	user = getenv("USER");

	/* Parse arguments */
	scriptfile = dumpfile = extensions = NULL;

	while ((c = master_getopt(master_service)) > 0) {
		switch (c) {
		case 'd':
			/* destination address */
			dumpfile = optarg;
			break;
		case 'x':
            /* destination address */
            extensions = optarg;
            break;
		case 't':
			trace = TRUE;
			break;
		default:
			print_help();
			i_fatal_status(EX_USAGE,
				"Unknown argument: %c", c);
			break;
		}
	}

	if ( optind < argc ) {
		scriptfile = t_strdup(argv[optind++]);
	} else {
		print_help();
		i_fatal_status(EX_USAGE, "Missing <scriptfile> argument");
	}
	
	if (optind != argc) {
		print_help();
		i_fatal_status(EX_USAGE, "Unknown argument: %s", argv[optind]);
	}

	/* Initialize mail user */
	home = _get_cwd();
	user = sieve_tool_get_user();

	env_put("DOVECONF_ENV=1");
	env_put(t_strdup_printf("HOME=%s", home));
	env_put(t_strdup_printf("MAIL=maildir:/tmp/dovecot-test-%s", user));

	master_service_init_finish(master_service);

	memset(&service_input, 0, sizeof(service_input));
	service_input.module = "testsuite";
	service_input.service = "testsuite";
	service_input.username = user;

	storage_service = mail_storage_service_init
		(master_service, NULL, service_flags);
	if ( mail_storage_service_lookup_next(storage_service, &service_input,
		&service_user, &mail_user_dovecot, &errstr) <= 0 )
		i_fatal("%s", errstr);

	/* Initialize testsuite */
	testsuite_tool_init(extensions);

	printf("Test case: %s:\n\n", scriptfile);

	/* Initialize environment */
	sieve_dir = strrchr(scriptfile, '/');
	if ( sieve_dir == NULL )
		sieve_dir= "./";
	else
		sieve_dir = t_strdup_until(scriptfile, sieve_dir+1);

	/* Currently needed for include (FIXME) */
	testsuite_setting_set
		("sieve_dir", t_strconcat(sieve_dir, "included", NULL));
	testsuite_setting_set
		("sieve_global_dir", t_strconcat(sieve_dir, "included-global", NULL));

	/* Compile sieve script */
	if ( (sbin = sieve_tool_script_compile(scriptfile, NULL)) != NULL ) {
		struct sieve_error_handler *ehandler;
		struct sieve_script_env scriptenv;

		/* Dump script */
		sieve_tool_dump_binary_to(sbin, dumpfile);
	
		testsuite_mailstore_init(user, home, mail_user_dovecot);

		if (master_service_set
			(master_service, "mail_full_filesystem_access=yes") < 0)
			i_unreached(); 

		testsuite_message_init(master_service, user, mail_user_dovecot);

		memset(&scriptenv, 0, sizeof(scriptenv));
		scriptenv.namespaces = testsuite_mailstore_get_namespace();
		scriptenv.default_mailbox = "INBOX";
		scriptenv.hostname = "testsuite.example.com";
		scriptenv.postmaster_address = "postmaster@example.com";
		scriptenv.username = user;
		scriptenv.smtp_open = testsuite_smtp_open;
		scriptenv.smtp_close = testsuite_smtp_close;
		scriptenv.trace_stream = ( trace ? o_stream_create_fd(1, 0, FALSE) : NULL );

		testsuite_scriptenv = &scriptenv;

		testsuite_result_init();

		/* Run the test */
		ehandler = sieve_stderr_ehandler_create(0);
		ret = testsuite_run(sbin, &testsuite_msgdata, &scriptenv, ehandler);
		sieve_error_handler_unref(&ehandler);

		switch ( ret ) {
		case SIEVE_EXEC_OK:
			break;
		case SIEVE_EXEC_FAILURE:
		case SIEVE_EXEC_KEEP_FAILED:
			testsuite_testcase_fail("execution aborted");
			break;
		case SIEVE_EXEC_BIN_CORRUPT:
			testsuite_testcase_fail("binary corrupt");
			break;
		default:
			testsuite_testcase_fail("unknown execution exit code");
		}

		sieve_close(&sbin);

		if ( scriptenv.trace_stream != NULL )
			o_stream_unref(&scriptenv.trace_stream);

		/* De-initialize message environment */
		testsuite_message_deinit();
		testsuite_mailstore_deinit();
		testsuite_result_deinit();
	} else {
		testsuite_testcase_fail("failed to compile testcase script");
	}

	/* De-initialize mail user */
	if ( mail_user_dovecot != NULL )
		mail_user_unref(&mail_user_dovecot);

	/* De-initialize testsuite */
	testsuite_tool_deinit();  

	mail_storage_service_user_free(&service_user);
	mail_storage_service_deinit(&storage_service);
	master_service_deinit(&master_service);

	return testsuite_testcase_result();
}

Consent

On this website, we use the web analytics service Matomo to analyze and review the use of our website. Through the collected statistics, we can improve our offerings and make them more appealing for you. Here, you can decide whether to allow us to process your data and set corresponding cookies for these purposes, in addition to technically necessary cookies. Further information on data protection—especially regarding "cookies" and "Matomo"—can be found in our privacy policy. You can withdraw your consent at any time.