diff options
Diffstat (limited to 'src/lib-storage/test-mailbox-list.c')
-rw-r--r-- | src/lib-storage/test-mailbox-list.c | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/src/lib-storage/test-mailbox-list.c b/src/lib-storage/test-mailbox-list.c new file mode 100644 index 0000000..aa8f62a --- /dev/null +++ b/src/lib-storage/test-mailbox-list.c @@ -0,0 +1,512 @@ +/* Copyright (c) 2019 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "str.h" +#include "test-common.h" +#include "mailbox-list-private.h" + +enum test_flags { + TEST_FLAG_NO_VNAME = BIT(0), + TEST_FLAG_NO_STORAGE_NAME = BIT(1), + TEST_FLAG_NO_MUTF7 = BIT(2), + TEST_FLAG_NO_UTF8 = BIT(3), +}; + +struct test_mailbox_list_name { + const char *vname; + const char *storage_name; + enum test_flags flags; + char *ns_prefix; + enum namespace_flags ns_flags; + char ns_sep; + char list_sep; + char vname_escape_char; + char storage_name_escape_char; + const char *maildir_name; +}; + +static char list_hierarchy_sep; +static char ns_sep[2] = { '\0', '\0' }; + +static void test_init_list(struct mailbox_list *list_r) +{ + i_zero(list_r); + list_r->ns = t_new(struct mail_namespace, 1); + list_r->ns->user = t_new(struct mail_user, 1); + list_r->ns->user->event = event_create(NULL); +} + +static void test_deinit_list(struct mailbox_list *list) +{ + mailbox_list_clear_error(list); + if (array_is_created(&list->error_stack)) { + mailbox_list_clear_error(list); + i_assert(array_count(&list->error_stack) == 0); + array_free(&list->error_stack); + } + event_unref(&list->ns->user->event); +} + +static void test_mailbox_list_errors(void) +{ + /* NOTE: keep in sync with test-mail-storage.c */ + struct mailbox_list list; + enum mail_error mail_error; + const char *errstr; + + test_begin("mail list errors"); + test_init_list(&list); + + /* try a regular error */ + mailbox_list_set_error(&list, MAIL_ERROR_PERM, "error1"); + test_assert(strcmp(mailbox_list_get_last_error(&list, &mail_error), + "error1") == 0); + test_assert(mail_error == MAIL_ERROR_PERM); + test_assert(strcmp(mailbox_list_get_last_internal_error(&list, &mail_error), + "error1") == 0); + test_assert(mail_error == MAIL_ERROR_PERM); + test_assert(!list.last_error_is_internal); + + /* set the error to itself */ + mailbox_list_set_error(&list, MAIL_ERROR_PARAMS, + mailbox_list_get_last_error(&list, &mail_error)); + test_assert(strcmp(mailbox_list_get_last_error(&list, &mail_error), + "error1") == 0); + test_assert(mail_error == MAIL_ERROR_PARAMS); + test_assert(strcmp(mailbox_list_get_last_internal_error(&list, &mail_error), + "error1") == 0); + test_assert(mail_error == MAIL_ERROR_PARAMS); + test_assert(!list.last_error_is_internal); + + /* clear the error - asking for it afterwards is a bug */ + mailbox_list_clear_error(&list); + test_assert(strcmp(mailbox_list_get_last_error(&list, &mail_error), + "BUG: Unknown internal list error") == 0); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(strcmp(mailbox_list_get_last_internal_error(&list, &mail_error), + "BUG: Unknown internal list error") == 0); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(!list.last_error_is_internal); + + /* set internal error in preparation for the next test */ + test_expect_error_string("critical0"); + mailbox_list_set_critical(&list, "critical0"); + test_expect_no_more_errors(); + test_assert(strstr(mailbox_list_get_last_error(&list, &mail_error), + MAIL_ERRSTR_CRITICAL_MSG) != NULL); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(strcmp(mailbox_list_get_last_internal_error(&list, &mail_error), + "critical0") == 0); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(list.last_error_is_internal); + + /* internal error without specifying what it is. this needs to clear + the previous internal error. */ + mailbox_list_set_internal_error(&list); + test_assert(strstr(mailbox_list_get_last_error(&list, &mail_error), + MAIL_ERRSTR_CRITICAL_MSG) != NULL); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(strstr(mailbox_list_get_last_internal_error(&list, &mail_error), + MAIL_ERRSTR_CRITICAL_MSG) != NULL); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(!list.last_error_is_internal); + + /* proper internal error */ + test_expect_error_string("critical1"); + mailbox_list_set_critical(&list, "critical1"); + test_expect_no_more_errors(); + test_assert(strstr(mailbox_list_get_last_error(&list, &mail_error), + MAIL_ERRSTR_CRITICAL_MSG) != NULL); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(strcmp(mailbox_list_get_last_internal_error(&list, &mail_error), + "critical1") == 0); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(list.last_error_is_internal); + + /* use it in the following internal error */ + test_expect_error_string("critical2: critical1"); + mailbox_list_set_critical(&list, "critical2: %s", + mailbox_list_get_last_internal_error(&list, &mail_error)); + test_expect_no_more_errors(); + test_assert(strstr(mailbox_list_get_last_error(&list, &mail_error), + MAIL_ERRSTR_CRITICAL_MSG) != NULL); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(strcmp(mailbox_list_get_last_internal_error(&list, &mail_error), + "critical2: critical1") == 0); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(list.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); + mailbox_list_set_critical(&list, "critical3: %s", + mailbox_list_get_last_error(&list, &mail_error)); + test_expect_no_more_errors(); + test_assert(strstr(mailbox_list_get_last_error(&list, &mail_error), + MAIL_ERRSTR_CRITICAL_MSG) != NULL); + test_assert(mail_error == MAIL_ERROR_TEMP); + errstr = mailbox_list_get_last_internal_error(&list, &mail_error); + test_assert(str_begins(errstr, "critical3: ")); + test_assert(strstr(errstr+11, MAIL_ERRSTR_CRITICAL_MSG) != NULL); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(list.last_error_is_internal); + + /* clear the error again and check that all is as expected */ + mailbox_list_clear_error(&list); + test_assert(strcmp(mailbox_list_get_last_error(&list, &mail_error), + "BUG: Unknown internal list error") == 0); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(strcmp(mailbox_list_get_last_internal_error(&list, &mail_error), + "BUG: Unknown internal list error") == 0); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(!list.last_error_is_internal); + + /* use internal error as a regular error (although that really + shouldn't be done) */ + test_expect_error_string("critical4"); + mailbox_list_set_critical(&list, "critical4"); + mailbox_list_set_error(&list, MAIL_ERROR_PARAMS, + mailbox_list_get_last_internal_error(&list, &mail_error)); + test_expect_no_more_errors(); + test_assert(strcmp(mailbox_list_get_last_error(&list, &mail_error), + "critical4") == 0); + test_assert(mail_error == MAIL_ERROR_PARAMS); + test_assert(strcmp(mailbox_list_get_last_internal_error(&list, &mail_error), + "critical4") == 0); + test_assert(mail_error == MAIL_ERROR_PARAMS); + test_assert(!list.last_error_is_internal); + + test_deinit_list(&list); + test_end(); +} + +static void test_mailbox_list_last_error_push_pop(void) +{ + /* NOTE: keep in sync with test-mail-storage.c */ + struct mailbox_list list; + enum mail_error mail_error; + + test_begin("mailbox_list_last_error_push/pop()"); + test_init_list(&list); + + /* regular error 1 */ + mailbox_list_set_error(&list, MAIL_ERROR_PERM, "regular error 1"); + mailbox_list_last_error_push(&list); + + /* critical error 1 */ + test_expect_error_string("critical error 1"); + mailbox_list_set_critical(&list, "critical error 1"); + test_expect_no_more_errors(); + mailbox_list_last_error_push(&list); + + /* regular error 2 */ + mailbox_list_set_error(&list, MAIL_ERROR_PARAMS, "regular error 2"); + mailbox_list_last_error_push(&list); + + /* critical error 2 */ + test_expect_error_string("critical error 2"); + mailbox_list_set_critical(&list, "critical error 2"); + test_expect_no_more_errors(); + mailbox_list_last_error_push(&list); + + /* -- clear all errors -- */ + mailbox_list_clear_error(&list); + + /* critical error 2 pop */ + mailbox_list_last_error_pop(&list); + test_assert(strstr(mailbox_list_get_last_error(&list, &mail_error), + MAIL_ERRSTR_CRITICAL_MSG) != NULL); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(strcmp(mailbox_list_get_last_internal_error(&list, &mail_error), + "critical error 2") == 0); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(list.last_error_is_internal); + + /* regular error 2 pop */ + mailbox_list_last_error_pop(&list); + test_assert(strcmp(mailbox_list_get_last_error(&list, &mail_error), + "regular error 2") == 0); + test_assert(mail_error == MAIL_ERROR_PARAMS); + test_assert(strcmp(mailbox_list_get_last_internal_error(&list, &mail_error), + "regular error 2") == 0); + test_assert(mail_error == MAIL_ERROR_PARAMS); + test_assert(!list.last_error_is_internal); + + /* critical error 1 pop */ + mailbox_list_last_error_pop(&list); + test_assert(strstr(mailbox_list_get_last_error(&list, &mail_error), + MAIL_ERRSTR_CRITICAL_MSG) != NULL); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(strcmp(mailbox_list_get_last_internal_error(&list, &mail_error), + "critical error 1") == 0); + test_assert(mail_error == MAIL_ERROR_TEMP); + test_assert(list.last_error_is_internal); + + /* regular error 1 pop */ + mailbox_list_last_error_pop(&list); + test_assert(strcmp(mailbox_list_get_last_error(&list, &mail_error), + "regular error 1") == 0); + test_assert(mail_error == MAIL_ERROR_PERM); + test_assert(strcmp(mailbox_list_get_last_internal_error(&list, &mail_error), + "regular error 1") == 0); + test_assert(mail_error == MAIL_ERROR_PERM); + test_assert(!list.last_error_is_internal); + + test_deinit_list(&list); + test_end(); +} + +static char +test_mailbox_list_get_hierarchy_sep(struct mailbox_list *list ATTR_UNUSED) +{ + return list_hierarchy_sep; +} + +static void +test_maibox_list_name_init(struct mailbox_list *list, + const struct test_mailbox_list_name *test, + bool mutf7) +{ + list->ns->prefix = test->ns_prefix == NULL ? "" : + test->ns_prefix; + list->ns->prefix_len = strlen(list->ns->prefix); + list->ns->flags = test->ns_flags; + ns_sep[0] = test->ns_sep; + list_hierarchy_sep = test->list_sep; + list->set.utf8 = !mutf7; + list->set.vname_escape_char = test->vname_escape_char; + list->set.storage_name_escape_char = + test->storage_name_escape_char; + list->set.maildir_name = test->maildir_name == NULL ? "" : + test->maildir_name; +} + +static void test_mailbox_list_get_names(void) +{ + const struct test_mailbox_list_name tests[] = { + { .vname = "parent/child", + .storage_name = "parent/child", + .ns_sep = '/', .list_sep = '/' }, + { .vname = "parent/child", + .storage_name = "parent.child", + .ns_sep = '/', .list_sep = '.' }, + { .vname = "ns_prefix/parent/child", + .storage_name = "parent.child", + .ns_prefix = "ns_prefix/", .ns_sep = '/', .list_sep = '.' }, + { .vname = "ns/prefix/parent/child", + .storage_name = "parent.child", + .ns_prefix = "ns/prefix/", .ns_sep = '/', .list_sep = '.' }, + { .vname = "ns/prefix", + .storage_name = "", + .ns_prefix = "ns/prefix/", .ns_sep = '/', .list_sep = '.' }, + { .vname = "\xC3\xA4/\xC3\xB6", + .storage_name = "&APY-", + .flags = TEST_FLAG_NO_UTF8, + .ns_prefix = "\xC3\xA4/", .ns_sep = '/', .list_sep = '.' }, + { .vname = "\xC3\xA4/\xC3\xB6&test", + .storage_name = "\xC3\xB6&test", + .flags = TEST_FLAG_NO_MUTF7, + .ns_prefix = "\xC3\xA4/", .ns_sep = '/', .list_sep = '.' }, + + /* storage_name escaping: */ + { .vname = "~home", + .storage_name = "%7ehome", + .ns_sep = '/', .list_sep = '.', + .storage_name_escape_char = '%' }, + { .vname = "es%cape%", + .storage_name = "es%25cape%25", + .ns_sep = '/', .list_sep = '.', + .storage_name_escape_char = '%' }, + { .vname = "slash/", + .storage_name = "slash%2f", + .ns_sep = '^', .list_sep = '.', + .storage_name_escape_char = '%' }, + { .vname = "list.separator", + .storage_name = "list%2eseparator", + .ns_sep = '/', .list_sep = '.', + .storage_name_escape_char = '%' }, + { .vname = "Maildir", + .storage_name = "%4daildir", + .ns_sep = '^', .list_sep = '.', + .storage_name_escape_char = '%', + .maildir_name = "Maildir" }, + { .vname = "~Maildir", + .storage_name = "%7eMaildir", + .ns_sep = '^', .list_sep = '.', + .storage_name_escape_char = '%', + .maildir_name = "Maildir" }, + { .vname = "Maildir/suffix", + .storage_name = "%4daildir%2fsuffix", + .ns_sep = '^', .list_sep = '.', + .storage_name_escape_char = '%', + .maildir_name = "Maildir" }, + { .vname = "prefix/Maildir", + .storage_name = "prefix%2f%4daildir", + .ns_sep = '^', .list_sep = '.', + .storage_name_escape_char = '%', + .maildir_name = "Maildir" }, + { .vname = "sep/Maildir/sep", + .storage_name = "sep.%4daildir.sep", + .ns_sep = '/', .list_sep = '.', + .storage_name_escape_char = '%', + .maildir_name = "Maildir" }, + { .vname = "~/.%--Maildir", + .storage_name = "%4daildir", + .ns_prefix = "~/.%--", + .ns_sep = '/', .list_sep = '.', + .storage_name_escape_char = '%', + .maildir_name = "Maildir" }, + { .vname = "%foo", + .storage_name = "%foo", + .flags = TEST_FLAG_NO_STORAGE_NAME, + .ns_sep = '/', .list_sep = '.', + .storage_name_escape_char = '%' }, + { .vname = "A/B.C%D", + .storage_name = "A.B%2eC%25D", + .storage_name_escape_char='%', + .ns_sep = '/', .list_sep = '.' }, + + /* vname escaping: */ + { .vname = "%7c|child", + .storage_name = "|.child", + .ns_sep = '|', .list_sep = '.', + .vname_escape_char = '%' }, + { .vname = "%7c|child.", + .storage_name = "|.child+2e", + .ns_sep = '|', .list_sep = '.', + .storage_name_escape_char = '+', + .vname_escape_char = '%' }, + { .vname = "%7c|child.", + .storage_name = "|.child%2e", + .ns_sep = '|', .list_sep = '.', + .storage_name_escape_char = '%', + .vname_escape_char = '%' }, + { .vname = "%2f/child", + .storage_name = "/.child", + .ns_sep = '/', .list_sep = '.', + .vname_escape_char = '%' }, + { .vname = "%2f/child.", + .storage_name = "+2f.child+2e", + .ns_sep = '/', .list_sep = '.', + .storage_name_escape_char = '+', + .vname_escape_char = '%' }, + { .vname = "%2f/child.", + .storage_name = "%2f.child%2e", + .ns_sep = '/', .list_sep = '.', + .storage_name_escape_char = '%', + .vname_escape_char = '%' }, + { .vname = "%25escaped+", + .storage_name = "%escaped+2b", + .ns_sep = '/', .list_sep = '.', + .storage_name_escape_char = '+', + .vname_escape_char = '%' }, + { .vname = "x%2666-y", + .storage_name = "x&66-y", + .flags = TEST_FLAG_NO_UTF8, + .ns_sep = '/', .list_sep = '.', + .vname_escape_char = '%' }, + { .vname = "p\xC3\xA4iv\xC3\xA4 & y%26APY %ff m\xC3\xB6h", + .storage_name = "p&AOQ-iv&AOQ- &- y&APY \xff m&APY-h", + .flags = TEST_FLAG_NO_UTF8, + .ns_sep = '/', .list_sep = '.', + .vname_escape_char = '%' }, + { .vname = "%foo", + .storage_name = "%foo", + .flags = TEST_FLAG_NO_VNAME, + .ns_sep = '/', .list_sep = '.', + .vname_escape_char = '%' }, + { .vname = "A%2fB/C%25D", + .storage_name = "A/B.C%D", + .ns_sep = '/', .list_sep = '.', + .vname_escape_char = '%' }, + + /* INBOX: */ + { .vname = "inBox", + .storage_name = "inBox", + .ns_sep = '/', .list_sep = '.' }, + { .vname = "inBox", + .storage_name = "INBOX", + .flags = TEST_FLAG_NO_VNAME, + .ns_flags = NAMESPACE_FLAG_INBOX_USER, + .ns_sep = '/', .list_sep = '.' }, + { .vname = "inBox", + .storage_name = "INBOX", + .flags = TEST_FLAG_NO_VNAME, + .ns_flags = NAMESPACE_FLAG_INBOX_USER, + .ns_prefix = "prefix/", .ns_sep = '/', .list_sep = '.' }, + { .vname = "prefix/inBox", + .storage_name = "inBox", + .ns_flags = NAMESPACE_FLAG_INBOX_USER, + .ns_prefix = "prefix/", .ns_sep = '/', .list_sep = '.' }, + { .vname = "prefix/INBOX", + .storage_name = "+49NBOX", + .ns_flags = NAMESPACE_FLAG_INBOX_USER, + .ns_prefix = "prefix/", .ns_sep = '/', .list_sep = '.', + .storage_name_escape_char = '+' }, + + /* Problematic cases - not reversible: */ + { .vname = "parent.child", + .storage_name = "parent.child", + .flags = TEST_FLAG_NO_VNAME, + .ns_sep = '/', .list_sep = '.' }, + { .vname = "prefix/INBOX", + .storage_name = "INBOX", + .flags = TEST_FLAG_NO_VNAME, + .ns_flags = NAMESPACE_FLAG_INBOX_USER, + .ns_prefix = "prefix/", .ns_sep = '/', .list_sep = '.' }, + { .vname = "invalid&mutf7", + .storage_name = "invalid&mutf7", + .flags = TEST_FLAG_NO_STORAGE_NAME, + .ns_sep = '/', .list_sep = '.' }, + }; + struct mail_namespace_settings ns_set = { + .separator = ns_sep, + }; + struct mail_namespace ns = { + .set = &ns_set, + }; + struct mailbox_list list = { + .ns = &ns, + .v = { + .get_hierarchy_sep = test_mailbox_list_get_hierarchy_sep, + }, + }; + + test_begin("mailbox list get names"); + for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) { + if ((tests[i].flags & TEST_FLAG_NO_MUTF7) == 0) { + test_maibox_list_name_init(&list, &tests[i], TRUE); + if ((tests[i].flags & TEST_FLAG_NO_STORAGE_NAME) == 0) { + test_assert_strcmp_idx(mailbox_list_default_get_storage_name(&list, tests[i].vname), + tests[i].storage_name, i); + } + if ((tests[i].flags & TEST_FLAG_NO_VNAME) == 0) { + test_assert_strcmp_idx(mailbox_list_default_get_vname(&list, tests[i].storage_name), + tests[i].vname, i); + } + } + if ((tests[i].flags & TEST_FLAG_NO_UTF8) == 0) { + test_maibox_list_name_init(&list, &tests[i], FALSE); + if ((tests[i].flags & TEST_FLAG_NO_STORAGE_NAME) == 0) { + test_assert_strcmp_idx(mailbox_list_default_get_storage_name(&list, tests[i].vname), + tests[i].storage_name, i); + } + if ((tests[i].flags & TEST_FLAG_NO_VNAME) == 0) { + test_assert_strcmp_idx(mailbox_list_default_get_vname(&list, tests[i].storage_name), + tests[i].vname, i); + } + } + } + test_end(); +} + +int main(void) +{ + void (*const tests[])(void) = { + test_mailbox_list_errors, + test_mailbox_list_last_error_push_pop, + test_mailbox_list_get_names, + NULL + }; + return test_run(tests); +} |