view src/lib-storage/test-mail-storage.c @ 22469:4b1e95fa17e8

lib-storage: Fix error logging after mail_storage_set_internal_error() The function doesn't actually set the last_internal_error and it also doesn't update last_error_is_internal, so calling mail_storage_get_last_internal_error() afterwards could be returning an error for some different older error. Since there's no parameter to set the internal error string, just reset last_error_is_internal=FALSE.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Mon, 21 Aug 2017 15:11:30 +0300
parents 41e9e1c79db3
children cb108f786fb4
line wrap: on
line source

/* Copyright (c) 2017 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "test-common.h"
#include "mail-storage-private.h"

static void test_mail_storage_errors(void)
{
	struct mail_storage storage;
	enum mail_error mail_error;
	const char *errstr;

	test_begin("mail storage errors");
	i_zero(&storage);

	/* try a regular error */
	mail_storage_set_error(&storage, MAIL_ERROR_PERM, "error1");
	test_assert(strcmp(mail_storage_get_last_error(&storage, &mail_error), "error1") == 0);
	test_assert(mail_error == MAIL_ERROR_PERM);
	test_assert(strcmp(mail_storage_get_last_internal_error(&storage, &mail_error), "error1") == 0);
	test_assert(mail_error == MAIL_ERROR_PERM);
	test_assert(!storage.last_error_is_internal);

	/* set the error to itself */
	mail_storage_set_error(&storage, MAIL_ERROR_PARAMS,
		mail_storage_get_last_error(&storage, &mail_error));
	test_assert(strcmp(mail_storage_get_last_error(&storage, &mail_error), "error1") == 0);
	test_assert(mail_error == MAIL_ERROR_PARAMS);
	test_assert(strcmp(mail_storage_get_last_internal_error(&storage, &mail_error), "error1") == 0);
	test_assert(mail_error == MAIL_ERROR_PARAMS);
	test_assert(!storage.last_error_is_internal);

	/* clear the error - asking for it afterwards is a bug */
	mail_storage_clear_error(&storage);
	test_assert(strcmp(mail_storage_get_last_error(&storage, &mail_error), "BUG: Unknown internal error") == 0);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(strcmp(mail_storage_get_last_internal_error(&storage, &mail_error), "BUG: Unknown internal error") == 0);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(!storage.last_error_is_internal);

	/* set internal error in preparation for the next test */
	test_expect_error_string("critical0");
	mail_storage_set_critical(&storage, "critical0");
	test_expect_no_more_errors();
	test_assert(strstr(mail_storage_get_last_error(&storage, &mail_error), MAIL_ERRSTR_CRITICAL_MSG) != NULL);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(strcmp(mail_storage_get_last_internal_error(&storage, &mail_error), "critical0") == 0);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(storage.last_error_is_internal);

	/* internal error without specifying what it is. this needs to clear
	   the previous internal error. */
	mail_storage_set_internal_error(&storage);
	test_assert(strstr(mail_storage_get_last_error(&storage, &mail_error), MAIL_ERRSTR_CRITICAL_MSG) != NULL);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(strstr(mail_storage_get_last_internal_error(&storage, &mail_error), MAIL_ERRSTR_CRITICAL_MSG) != NULL);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(!storage.last_error_is_internal);

	/* proper internal error */
	test_expect_error_string("critical1");
	mail_storage_set_critical(&storage, "critical1");
	test_expect_no_more_errors();
	test_assert(strstr(mail_storage_get_last_error(&storage, &mail_error), MAIL_ERRSTR_CRITICAL_MSG) != NULL);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(strcmp(mail_storage_get_last_internal_error(&storage, &mail_error), "critical1") == 0);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(storage.last_error_is_internal);

	/* use it in the following internal error */
	test_expect_error_string("critical2: critical1");
	mail_storage_set_critical(&storage, "critical2: %s",
		mail_storage_get_last_internal_error(&storage, &mail_error));
	test_expect_no_more_errors();
	test_assert(strstr(mail_storage_get_last_error(&storage, &mail_error), MAIL_ERRSTR_CRITICAL_MSG) != NULL);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(strcmp(mail_storage_get_last_internal_error(&storage, &mail_error), "critical2: critical1") == 0);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(storage.last_error_is_internal);

	/* use the previous non-internal error as part of the internal error */
	test_expect_error_string("critical3: "MAIL_ERRSTR_CRITICAL_MSG);
	mail_storage_set_critical(&storage, "critical3: %s",
		mail_storage_get_last_error(&storage, &mail_error));
	test_expect_no_more_errors();
	test_assert(strstr(mail_storage_get_last_error(&storage, &mail_error), MAIL_ERRSTR_CRITICAL_MSG) != NULL);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	errstr = mail_storage_get_last_internal_error(&storage, &mail_error);
	test_assert(strncmp(errstr, "critical3: ", 11) == 0);
	test_assert(strstr(errstr+11, MAIL_ERRSTR_CRITICAL_MSG) != NULL);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(storage.last_error_is_internal);

	/* clear the error again and check that all is as expected */
	mail_storage_clear_error(&storage);
	test_assert(strcmp(mail_storage_get_last_error(&storage, &mail_error), "BUG: Unknown internal error") == 0);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(strcmp(mail_storage_get_last_internal_error(&storage, &mail_error), "BUG: Unknown internal error") == 0);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(!storage.last_error_is_internal);

	/* use internal error as a regular error (although that really
	   shouldn't be done) */
	test_expect_error_string("critical4");
	mail_storage_set_critical(&storage, "critical4");
	mail_storage_set_error(&storage, MAIL_ERROR_PARAMS,
		mail_storage_get_last_internal_error(&storage, &mail_error));
	test_expect_no_more_errors();
	test_assert(strcmp(mail_storage_get_last_error(&storage, &mail_error), "critical4") == 0);
	test_assert(mail_error == MAIL_ERROR_PARAMS);
	test_assert(strcmp(mail_storage_get_last_internal_error(&storage, &mail_error), "critical4") == 0);
	test_assert(mail_error == MAIL_ERROR_PARAMS);
	test_assert(!storage.last_error_is_internal);

	mail_storage_clear_error(&storage);
	test_end();
}

static void test_mail_storage_last_error_push_pop(void)
{
	struct mail_storage storage;
	enum mail_error mail_error;

	test_begin("mail_storage_last_error_push/pop()");
	i_zero(&storage);

	/* regular error 1 */
	mail_storage_set_error(&storage, MAIL_ERROR_PERM, "regular error 1");
	mail_storage_last_error_push(&storage);

	/* critical error 1 */
	test_expect_error_string("critical error 1");
	mail_storage_set_critical(&storage, "critical error 1");
	test_expect_no_more_errors();
	mail_storage_last_error_push(&storage);

	/* regular error 2 */
	mail_storage_set_error(&storage, MAIL_ERROR_PARAMS, "regular error 2");
	mail_storage_last_error_push(&storage);

	/* critical error 2 */
	test_expect_error_string("critical error 2");
	mail_storage_set_critical(&storage, "critical error 2");
	test_expect_no_more_errors();
	mail_storage_last_error_push(&storage);

	/* -- clear all errors -- */
	mail_storage_clear_error(&storage);

	/* critical error 2 pop */
	mail_storage_last_error_pop(&storage);
	test_assert(strstr(mail_storage_get_last_error(&storage, &mail_error), MAIL_ERRSTR_CRITICAL_MSG) != NULL);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(strcmp(mail_storage_get_last_internal_error(&storage, &mail_error), "critical error 2") == 0);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(storage.last_error_is_internal);

	/* regular error 2 pop */
	mail_storage_last_error_pop(&storage);
	test_assert(strcmp(mail_storage_get_last_error(&storage, &mail_error), "regular error 2") == 0);
	test_assert(mail_error == MAIL_ERROR_PARAMS);
	test_assert(strcmp(mail_storage_get_last_internal_error(&storage, &mail_error), "regular error 2") == 0);
	test_assert(mail_error == MAIL_ERROR_PARAMS);
	test_assert(!storage.last_error_is_internal);

	/* critical error 1 pop */
	mail_storage_last_error_pop(&storage);
	test_assert(strstr(mail_storage_get_last_error(&storage, &mail_error), MAIL_ERRSTR_CRITICAL_MSG) != NULL);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(strcmp(mail_storage_get_last_internal_error(&storage, &mail_error), "critical error 1") == 0);
	test_assert(mail_error == MAIL_ERROR_TEMP);
	test_assert(storage.last_error_is_internal);

	/* regular error 1 pop */
	mail_storage_last_error_pop(&storage);
	test_assert(strcmp(mail_storage_get_last_error(&storage, &mail_error), "regular error 1") == 0);
	test_assert(mail_error == MAIL_ERROR_PERM);
	test_assert(strcmp(mail_storage_get_last_internal_error(&storage, &mail_error), "regular error 1") == 0);
	test_assert(mail_error == MAIL_ERROR_PERM);
	test_assert(!storage.last_error_is_internal);

	mail_storage_clear_error(&storage);
	i_assert(array_count(&storage.error_stack) == 0);
	array_free(&storage.error_stack);
	test_end();
}

int main(void)
{
	static void (*test_functions[])(void) = {
		test_mail_storage_errors,
		test_mail_storage_last_error_push_pop,
		NULL
	};

	return test_run(test_functions);
}