diff options
author | Guilhem Moulin <guilhem@fripost.org> | 2019-11-13 06:24:07 +0100 |
---|---|---|
committer | Guilhem Moulin <guilhem@fripost.org> | 2019-11-13 06:24:07 +0100 |
commit | c6bbdd8aa697b2d42be1ac0839189da32d437a8f (patch) | |
tree | cd1b8d19d99557fbebe33344d0d23f6ac826da57 /tests | |
parent | 87d947df1b837514a0f1efa3bc36b58088bd2564 (diff) | |
parent | dac4ab1c9306bf2035bc1547d2ed27ab09850120 (diff) |
Merge branch 'master' into debian
Diffstat (limited to 'tests')
173 files changed, 1681 insertions, 659 deletions
diff --git a/tests/00-db-exclusive/local.conf b/tests/00-db-exclusive/local.conf deleted file mode 100644 index 9c838fd..0000000 --- a/tests/00-db-exclusive/local.conf +++ /dev/null @@ -1,5 +0,0 @@ -namespace inbox { - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/00-db-exclusive/remote.conf b/tests/00-db-exclusive/remote.conf deleted file mode 100644 index 9c838fd..0000000 --- a/tests/00-db-exclusive/remote.conf +++ /dev/null @@ -1,5 +0,0 @@ -namespace inbox { - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/00-db-exclusive/run b/tests/00-db-exclusive/run deleted file mode 100644 index 1528b3b..0000000 --- a/tests/00-db-exclusive/run +++ /dev/null @@ -1,25 +0,0 @@ -# verify that database isn't created in --watch mode -! interimap --watch=60 -xgrep -E "^DBI connect\(.*\) failed: unable to open database file at " <"$STDERR" - -# now create database -interimap - -# start a background process -interimap --watch=60 & pid=$! -cleanup() { - # kill interimap process and its children - pkill -P "$pid" -TERM || true - kill -TERM "$pid" || true - wait -} -trap cleanup EXIT INT TERM - -sleep .05 # wait a short while so we have time to lock the database (ugly and racy...) -# verify that subsequent runs fail as we can't acquire the exclusive lock -! interimap - -# line 177 is `$DBH->do("PRAGMA locking_mode = EXCLUSIVE");` -xgrep -Fx "DBD::SQLite::db do failed: database is locked at ./interimap line 177." <"$STDERR" - -# vim: set filetype=sh : diff --git a/tests/00-db-migration-0-to-1-delim-mismatch/before.sql b/tests/00-db-migration-0-to-1-delim-mismatch/before.sql deleted file mode 120000 index 0abb9bf..0000000 --- a/tests/00-db-migration-0-to-1-delim-mismatch/before.sql +++ /dev/null @@ -1 +0,0 @@ -../00-db-migration-0-to-1/before.sql
\ No newline at end of file diff --git a/tests/00-db-migration-0-to-1-delim-mismatch/local.conf b/tests/00-db-migration-0-to-1-delim-mismatch/local.conf deleted file mode 100644 index 08438cb..0000000 --- a/tests/00-db-migration-0-to-1-delim-mismatch/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = "\"" - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/00-db-migration-0-to-1-delim-mismatch/remote.conf b/tests/00-db-migration-0-to-1-delim-mismatch/remote.conf deleted file mode 100644 index cc6781d..0000000 --- a/tests/00-db-migration-0-to-1-delim-mismatch/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ^ - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/00-db-migration-0-to-1-delim-mismatch/run b/tests/00-db-migration-0-to-1-delim-mismatch/run deleted file mode 100644 index 434c678..0000000 --- a/tests/00-db-migration-0-to-1-delim-mismatch/run +++ /dev/null @@ -1,8 +0,0 @@ -# import an existing non-migrated database -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <"$TESTDIR/before.sql" -! interimap - -# may happen if the server(s) software or its configuration changed -xgrep -Fx 'ERROR: Local and remote hierachy delimiters differ (local "\"", remote "^"), refusing to update `mailboxes` table.' <"$STDERR" - -# vim: set filetype=sh : diff --git a/tests/00-db-migration-0-to-1-foreign-key-violation/local.conf b/tests/00-db-migration-0-to-1-foreign-key-violation/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/00-db-migration-0-to-1-foreign-key-violation/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/00-db-migration-0-to-1-foreign-key-violation/remote.conf b/tests/00-db-migration-0-to-1-foreign-key-violation/remote.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/00-db-migration-0-to-1-foreign-key-violation/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/00-db-migration-0-to-1-foreign-key-violation/run b/tests/00-db-migration-0-to-1-foreign-key-violation/run deleted file mode 100644 index f2d12a9..0000000 --- a/tests/00-db-migration-0-to-1-foreign-key-violation/run +++ /dev/null @@ -1,23 +0,0 @@ -# create new schema and add INBOX -interimap -xgrep "^Creating new schema in database file " <"$STDERR" -xgrep -Fx "database: Created mailbox INBOX" <"$STDERR" - -# empty table `mailboxes` and revert its schema to version 0 -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <<-EOF - PRAGMA foreign_keys = OFF; - PRAGMA user_version = 0; - DROP TABLE mailboxes; - CREATE TABLE mailboxes ( - idx INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - mailbox TEXT NOT NULL CHECK (mailbox != '') UNIQUE, - subscribed BOOLEAN NOT NULL - ); -EOF - -# check that migration fails due to broken referential integrity -! interimap -xgrep -Fx "Upgrading database version from 0" <"$STDERR" -xgrep -Fx "database: ERROR: Broken referential integrity! Refusing to commit changes." <"$STDERR" - -# vim: set filetype=sh : diff --git a/tests/00-db-migration-0-to-1/local.conf b/tests/00-db-migration-0-to-1/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/00-db-migration-0-to-1/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/00-db-migration-0-to-1/remote.conf b/tests/00-db-migration-0-to-1/remote.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/00-db-migration-0-to-1/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/01-rename-exists-db/local.conf b/tests/01-rename-exists-db/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/01-rename-exists-db/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/01-rename-exists-db/remote.conf b/tests/01-rename-exists-db/remote.conf deleted file mode 100644 index 61e3d0d..0000000 --- a/tests/01-rename-exists-db/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = "\\" - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/01-rename-exists-local/local.conf b/tests/01-rename-exists-local/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/01-rename-exists-local/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/01-rename-exists-local/remote.conf b/tests/01-rename-exists-local/remote.conf deleted file mode 100644 index 61e3d0d..0000000 --- a/tests/01-rename-exists-local/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = "\\" - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/01-rename-exists-remote/local.conf b/tests/01-rename-exists-remote/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/01-rename-exists-remote/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/01-rename-exists-remote/remote.conf b/tests/01-rename-exists-remote/remote.conf deleted file mode 100644 index 61e3d0d..0000000 --- a/tests/01-rename-exists-remote/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = "\\" - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/01-rename/local.conf b/tests/01-rename/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/01-rename/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/01-rename/remote.conf b/tests/01-rename/remote.conf deleted file mode 100644 index cc6781d..0000000 --- a/tests/01-rename/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ^ - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/02-delete/local.conf b/tests/02-delete/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/02-delete/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/02-delete/remote.conf b/tests/02-delete/remote.conf deleted file mode 100644 index cc6781d..0000000 --- a/tests/02-delete/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ^ - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/03-sync-mailbox-list-partial/interimap.conf b/tests/03-sync-mailbox-list-partial/interimap.conf deleted file mode 100644 index 4970867..0000000 --- a/tests/03-sync-mailbox-list-partial/interimap.conf +++ /dev/null @@ -1 +0,0 @@ -list-mailbox = * diff --git a/tests/03-sync-mailbox-list-partial/local.conf b/tests/03-sync-mailbox-list-partial/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/03-sync-mailbox-list-partial/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/03-sync-mailbox-list-partial/remote.conf b/tests/03-sync-mailbox-list-partial/remote.conf deleted file mode 100644 index 352cdd4..0000000 --- a/tests/03-sync-mailbox-list-partial/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ~ - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/03-sync-mailbox-list-partial/run b/tests/03-sync-mailbox-list-partial/run deleted file mode 100644 index 449115d..0000000 --- a/tests/03-sync-mailbox-list-partial/run +++ /dev/null @@ -1,57 +0,0 @@ -# try a bunch of invalid 'list-mailbox' values: -# empty string, missing space between values, unterminated string -for v in '""' '"f o o""bar"' '"f o o" "bar" "baz\" x'; do - sed -ri "s/^(list-mailbox\\s*=\\s*).*/\\1${v//\\/\\\\}/" "$XDG_CONFIG_HOME/interimap/config" - ! interimap - xgrep -xF "Invalid value for list-mailbox: $v" <"$STDERR" -done - -# create some mailboxes -doveadm -u "local" mailbox create "foo" "foo bar" "f\\\"o!o.bar" "f.o.o" "bad" -for m in "foo" "foo bar" "f\\\"o!o.bar" "f.o.o" "bad" "INBOX"; do - sample_message | deliver -u "local" -- -m "$m" -done - -# restrict 'list-mailbox' to the above minus "bad" -sed -ri 's/^(list-mailbox\s*=\s*).*/\1foo "foo bar" "f\\\\\\"o\\x21o.*" "f\\0o\\0o"/' \ - "$XDG_CONFIG_HOME/interimap/config" - -# run partial sync -interimap -check_mailbox_list "foo" "foo bar" "f\\\"o!o.bar" "f.o.o" "INBOX" "f\\\"o!o" "f" "f.o" -check_mailboxes_status "foo" "foo bar" "f\\\"o!o.bar" "f.o.o" - -# check that "bad" isn't in the remote imap server -! doveadm -u "remote" mailbox status uidvalidity "bad" - -# check that "bad" and "INBOX" aren't in the database -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/count" <<-EOF - SELECT COUNT(*) - FROM mailboxes - WHERE mailbox = x'$(printf "%s" "bad" | xxd -ps)' - OR mailbox = x'$(printf "%s" "INBOX" | xxd -ps)' -EOF -[ $(< "$TMPDIR/count") -eq 0 ] - - -# run partial sync -doveadm -u "remote" mailbox create "f\\\"o!o~baz" "f\\\"o!o~bad" -for m in "f\\\"o!o~baz" "f\\\"o!o~bad"; do - sample_message | deliver -u "remote" -- -m "$m" -done -interimap "f\\\"o!o.baz" - -check_mailbox_list "foo" "foo bar" "f\\\"o!o.bar" "f.o.o" "INBOX" "f\\\"o!o" "f" "f.o" "f\\\"o!o.baz" -check_mailboxes_status "foo" "foo bar" "f\\\"o!o.bar" "f.o.o" "f\\\"o!o.baz" - -# check that "bad", "f\\\"o!o.bad" and "INBOX" aren't in the database -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/count" <<-EOF - SELECT COUNT(*) - FROM mailboxes - WHERE mailbox = x'$(printf "%s" "bad" | xxd -ps)' - OR mailbox = x'$(printf "%s" "INBOX" | xxd -ps)' - OR mailbox = x'$(printf "%s\\0%s" "f\\\"o!o" "bad" | xxd -ps)' -EOF -[ $(< "$TMPDIR/count") -eq 0 ] - -# vim: set filetype=sh : diff --git a/tests/03-sync-mailbox-list-ref/local.conf b/tests/03-sync-mailbox-list-ref/local.conf deleted file mode 100644 index 6eccf43..0000000 --- a/tests/03-sync-mailbox-list-ref/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = / - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/03-sync-mailbox-list-ref/remote.conf b/tests/03-sync-mailbox-list-ref/remote.conf deleted file mode 100644 index 61e3d0d..0000000 --- a/tests/03-sync-mailbox-list-ref/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = "\\" - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/03-sync-mailbox-list-ref/run b/tests/03-sync-mailbox-list-ref/run deleted file mode 100644 index 3ead25d..0000000 --- a/tests/03-sync-mailbox-list-ref/run +++ /dev/null @@ -1,28 +0,0 @@ -# Note: implementation-dependent as the reference name is not a level of -# mailbox hierarchy nor ends with the hierarchy delimiter -sed -ri 's#^\[local\]$#&\nlist-reference = foo#; s#^\[remote\]$#&\nlist-reference = bar#' \ - "$XDG_CONFIG_HOME/interimap/config" - -# create a bunch of mailboxes in and out the respective list # references -doveadm -u "local" mailbox create "foo" "foobar" "foo/bar/baz" "foo/baz" "bar" -doveadm -u "remote" mailbox create "foo" - -# deliver somemessages to these mailboxes -for m in "foo" "foobar" "foo/bar/baz" "foo/baz" "bar"; do - sample_message | deliver -u "local" -- -m "$m" -done -sample_message | deliver -u "remote" -- -m "foo" - -interimap - -# check that the mailbox lists match -diff -u --label="local/mailboxes" --label="remote/mailboxes" \ - <( doveadm -u "local" mailbox list | sed -n "s/^foo//p" | sort ) \ - <( doveadm -u "remote" mailbox list | sed -n "s/^bar//p" | tr '\\' '/' | sort ) - -for m in "" "bar" "/bar/baz" "/baz"; do - blob="x'$(printf "%s" "$m" | tr "/" "\\0" | xxd -c256 -ps)'" - check_mailbox_status2 "$blob" "foo$m" "remote" "bar${m//\//\\}" -done - -# vim: set filetype=sh : diff --git a/tests/03-sync-mailbox-list/local.conf b/tests/03-sync-mailbox-list/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/03-sync-mailbox-list/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/03-sync-mailbox-list/remote.conf b/tests/03-sync-mailbox-list/remote.conf deleted file mode 100644 index 352cdd4..0000000 --- a/tests/03-sync-mailbox-list/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ~ - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/03-sync-mailbox-list/run b/tests/03-sync-mailbox-list/run deleted file mode 100644 index b506204..0000000 --- a/tests/03-sync-mailbox-list/run +++ /dev/null @@ -1,73 +0,0 @@ -# pre-create some mailboxes and susbscribe to some -# foo: present on both, subscribed to both -# bar: present on both, subscribed to local only -# baz: present on both, subscribed to remote only -# foo.bar: present on local only -# foo.baz: present on remote only -doveadm -u "local" mailbox create "foo" "bar" "baz" "foo.bar" "fo!o [b*a%r]" -doveadm -u "local" mailbox subscribe "foo" "bar" -doveadm -u "remote" mailbox create "foo" "bar" "baz" "foo~baz" "foo]bar" -doveadm -u "remote" mailbox subscribe "foo" "baz" - -interimap -xgrep -Fx "local: Subscribe to baz" <"$STDERR" -xgrep -Fx "remote: Subscribe to bar" <"$STDERR" -xgrep -Fx "local: Created mailbox foo.baz" <"$STDERR" -xgrep -Fx "remote: Created mailbox foo~bar" <"$STDERR" - -# check syncing -check_mailbox_list -check_mailboxes_status "foo" "bar" "baz" "foo.bar" "foo.baz" "INBOX" "fo!o [b*a%r]" "foo]bar" -check_mailbox_list -s - - -# delete a mailbox one server and verify that synchronization fails as it's still in the database -doveadm -u "remote" mailbox delete "foo~baz" -! interimap -xgrep -Fx 'database: ERROR: Mailbox foo.baz exists. Run `interimap --target=database --delete foo.baz` to delete.' <"$STDERR" -interimap --target="database" --delete "foo.baz" -xgrep -Fx 'database: Removed mailbox foo.baz' <"$STDERR" -interimap # create again -xgrep -Fx 'database: Created mailbox foo.baz' <"$STDERR" -xgrep -Fx 'remote: Created mailbox foo~baz' <"$STDERR" - -doveadm -u "local" mailbox delete "foo.bar" -! interimap -xgrep -Fx 'database: ERROR: Mailbox foo.bar exists. Run `interimap --target=database --delete foo.bar` to delete.' <"$STDERR" -interimap --target="database" --delete "foo.bar" -xgrep -Fx 'database: Removed mailbox foo.bar' <"$STDERR" -interimap -xgrep -Fx 'database: Created mailbox foo.bar' <"$STDERR" -xgrep -Fx 'local: Created mailbox foo.bar' <"$STDERR" - -check_mailbox_list -check_mailboxes_status "foo" "bar" "baz" "foo.bar" "foo.baz" "INBOX" "fo!o [b*a%r]" "foo]bar" -check_mailbox_list -s - - -# (un)subscribe from some mailboxes, including a non-existent one -doveadm -u "local" mailbox unsubscribe "foo" -doveadm -u "remote" mailbox unsubscribe "bar" -doveadm -u "local" mailbox subscribe "foo.bar" "foo.nonexistent" "foo.baz" -doveadm -u "remote" mailbox subscribe "foo~bar" "bar~nonexistent" - -interimap -xgrep -Fx 'remote: Unsubscribe to foo' <"$STDERR" -xgrep -Fx 'local: Unsubscribe to bar' <"$STDERR" -xgrep -Fx 'remote: Subscribe to foo~baz' <"$STDERR" -check_mailbox_list -check_mailbox_list -s $(doveadm -u "local" mailbox list) # exclude "foo.nonexistent" and "bar~nonexistent" - -# check that "baz", "foo.bar" and "foo.baz" are the only subscribed mailboxes -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/count" <<-EOF - SELECT COUNT(*) - FROM mailboxes - WHERE subscribed <> (mailbox IN ( - x'$(printf "%s" "baz" | xxd -ps)', - x'$(printf "%s\\0%s" "foo" "bar" | xxd -ps)', - x'$(printf "%s\\0%s" "foo" "baz" | xxd -ps)' - )) -EOF -[ $(< "$TMPDIR/count") -eq 0 ] - -# vim: set filetype=sh : diff --git a/tests/04-resume/local.conf b/tests/04-resume/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/04-resume/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/04-resume/remote.conf b/tests/04-resume/remote.conf deleted file mode 100644 index 352cdd4..0000000 --- a/tests/04-resume/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ~ - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/05-repair/local.conf b/tests/05-repair/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/05-repair/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/05-repair/remote.conf b/tests/05-repair/remote.conf deleted file mode 100644 index 352cdd4..0000000 --- a/tests/05-repair/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ~ - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/06-largeint/local.conf b/tests/06-largeint/local.conf deleted file mode 100644 index 9c838fd..0000000 --- a/tests/06-largeint/local.conf +++ /dev/null @@ -1,5 +0,0 @@ -namespace inbox { - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/06-largeint/remote.conf b/tests/06-largeint/remote.conf deleted file mode 100644 index 9c838fd..0000000 --- a/tests/06-largeint/remote.conf +++ /dev/null @@ -1,5 +0,0 @@ -namespace inbox { - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/07-sync-live-multi/remote.conf b/tests/07-sync-live-multi/remote.conf deleted file mode 100644 index 3267182..0000000 --- a/tests/07-sync-live-multi/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ^ - location = dbox:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/07-sync-live-multi/remote2.conf b/tests/07-sync-live-multi/remote2.conf deleted file mode 100644 index 062429e..0000000 --- a/tests/07-sync-live-multi/remote2.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = "\\" - location = dbox:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/07-sync-live-multi/remote3.conf b/tests/07-sync-live-multi/remote3.conf deleted file mode 100644 index a4b9b1c..0000000 --- a/tests/07-sync-live-multi/remote3.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = "?" - location = dbox:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/07-sync-live/local.conf b/tests/07-sync-live/local.conf deleted file mode 100644 index 1333540..0000000 --- a/tests/07-sync-live/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = dbox:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/07-sync-live/remote.conf b/tests/07-sync-live/remote.conf deleted file mode 100644 index 3267182..0000000 --- a/tests/07-sync-live/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ^ - location = dbox:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/auth-login/interimap.remote b/tests/auth-login/interimap.remote new file mode 100644 index 0000000..b7d67bf --- /dev/null +++ b/tests/auth-login/interimap.remote @@ -0,0 +1,5 @@ +type = imap +host = localhost +port = 10143 +STARTTLS = NO +auth = login diff --git a/tests/auth-login/remote.conf b/tests/auth-login/remote.conf new file mode 100644 index 0000000..4ab127a --- /dev/null +++ b/tests/auth-login/remote.conf @@ -0,0 +1,2 @@ +!include conf.d/imapd.conf +auth_mechanisms = plain login diff --git a/tests/auth-login/t b/tests/auth-login/t new file mode 100644 index 0000000..7fd83d5 --- /dev/null +++ b/tests/auth-login/t @@ -0,0 +1,12 @@ +for ((i = 0; i < 32; i++)); do + u="$(shuf -n1 -e "local" "remote")" + sample_message | deliver -u "$u" +done + +# check that credentials aren't leaked to the debug output +interimap --debug || error +grep -Fx "remote: C: xxx LOGIN [REDACTED]" <"$STDERR" || error + +check_mailbox_status "INBOX" + +# vim: set filetype=sh : diff --git a/tests/auth-logindisabled/interimap.remote b/tests/auth-logindisabled/interimap.remote new file mode 120000 index 0000000..a4ea3f3 --- /dev/null +++ b/tests/auth-logindisabled/interimap.remote @@ -0,0 +1 @@ +../auth-sasl-plain/interimap.remote
\ No newline at end of file diff --git a/tests/auth-logindisabled/remote.conf b/tests/auth-logindisabled/remote.conf new file mode 100644 index 0000000..1f02afe --- /dev/null +++ b/tests/auth-logindisabled/remote.conf @@ -0,0 +1,4 @@ +!include conf.d/imapd.conf + +# trick dovecot into treating local connections as insecure +imap_capability = +LOGINDISABLED diff --git a/tests/auth-logindisabled/t b/tests/auth-logindisabled/t new file mode 100644 index 0000000..0bcd0d6 --- /dev/null +++ b/tests/auth-logindisabled/t @@ -0,0 +1,16 @@ +! interimap --debug || error + +# double check the presence of 'LOGINDISABLED' in the preauth capability list +grep -oE -m1 '^remote: S: \* OK \[CAPABILITY IMAP4rev1( [^]]*)? AUTH=[^]]*\]' <"$STDERR" >"$TMPDIR/capability" + +sed -ri 's/^remote: S: \* OK \[CAPABILITY (.*)\]$/\1/' "$TMPDIR/capability" +tr " " "\\n" <"$TMPDIR/capability" >"$TMPDIR/capabilities" +grep -Fx "IMAP4rev1" <"$TMPDIR/capabilities" || error +grep -Fx "LOGINDISABLED" <"$TMPDIR/capabilities" || error +! grep -Fx "STARTTLS" <"$TMPDIR/capabilities" || error # otherwise we'd try to upgrade the connectionn + +# make sure we didn't send any credentials +grep -Fx "remote: ERROR: Logins are disabled." <"$STDERR" || error +! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error + +# vim: set filetype=sh : diff --git a/tests/auth-noplaintext/interimap.remote b/tests/auth-noplaintext/interimap.remote new file mode 100644 index 0000000..60567e2 --- /dev/null +++ b/tests/auth-noplaintext/interimap.remote @@ -0,0 +1,3 @@ +type = imap +host = localhost +port = 10143 diff --git a/tests/auth-noplaintext/remote.conf b/tests/auth-noplaintext/remote.conf new file mode 120000 index 0000000..dbbb908 --- /dev/null +++ b/tests/auth-noplaintext/remote.conf @@ -0,0 +1 @@ +../auth-sasl-plain/remote.conf
\ No newline at end of file diff --git a/tests/auth-noplaintext/t b/tests/auth-noplaintext/t new file mode 100644 index 0000000..11d7d4d --- /dev/null +++ b/tests/auth-noplaintext/t @@ -0,0 +1,15 @@ +! interimap --debug || error + +# double check the presence of 'STARTTLS' in the preauth capability list +grep -oE -m1 '^remote: S: \* OK \[CAPABILITY IMAP4rev1( [^]]*)? AUTH=[^]]*\]' <"$STDERR" >"$TMPDIR/capability" + +sed -ri 's/^remote: S: \* OK \[CAPABILITY (.*)\]$/\1/' "$TMPDIR/capability" +tr " " "\\n" <"$TMPDIR/capability" >"$TMPDIR/capabilities" + grep -Fx "IMAP4rev1" <"$TMPDIR/capabilities" || error +! grep -Fx "STARTTLS" <"$TMPDIR/capabilities" || error + +# make sure we didn't send any credentials +grep -Fx "remote: ERROR: Server did not advertise STARTTLS capability." <"$STDERR" || error +! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error + +# vim: set filetype=sh : diff --git a/tests/auth-sasl-plain-no-ir/interimap.remote b/tests/auth-sasl-plain-no-ir/interimap.remote new file mode 120000 index 0000000..a4ea3f3 --- /dev/null +++ b/tests/auth-sasl-plain-no-ir/interimap.remote @@ -0,0 +1 @@ +../auth-sasl-plain/interimap.remote
\ No newline at end of file diff --git a/tests/auth-sasl-plain-no-ir/remote.conf b/tests/auth-sasl-plain-no-ir/remote.conf new file mode 100644 index 0000000..dae9545 --- /dev/null +++ b/tests/auth-sasl-plain-no-ir/remote.conf @@ -0,0 +1,2 @@ +!include conf.d/imapd.conf +!include conf.d/interimap-required-capabilities.conf diff --git a/tests/auth-sasl-plain-no-ir/t b/tests/auth-sasl-plain-no-ir/t new file mode 100644 index 0000000..17aa9e6 --- /dev/null +++ b/tests/auth-sasl-plain-no-ir/t @@ -0,0 +1,26 @@ +n=1 # at least one message to send remotely +sample_message | deliver -u "local" +for ((i = 0; i < 32; i++)); do + u="$(shuf -n1 -e "local" "remote")" + [ "$u" = "remote" ] || n=$(( n+1 )) + sample_message | deliver -u "$u" +done + +# check that credentials aren't leaked to the debug output +interimap --debug || error +grep -Fx "remote: C: xxx AUTHENTICATE PLAIN [REDACTED]" <"$STDERR" || error + +# make sure we didn't use SASL-IR +grep -oE -m1 '^remote: S: \* OK \[CAPABILITY IMAP4rev1( [^]]*)? AUTH=[^]]*\]' <"$STDERR" >"$TMPDIR/capability" + +sed -ri 's/^remote: S: \* OK \[CAPABILITY (.*)\]$/\1/' "$TMPDIR/capability" +tr " " "\\n" <"$TMPDIR/capability" >"$TMPDIR/capabilities" + grep -Fx "IMAP4rev1" <"$TMPDIR/capabilities" || error +! grep -Fx "SASL-IR" <"$TMPDIR/capabilities" || error + +# make sure all literals were synchronizing (and that we didn't use MULTIAPPEND) +xcgrep "$n" -E "^remote(\(INBOX\))?: C: [0-9]+ APPEND INBOX .* \{[0-9]+\}$" <"$STDERR" + +check_mailbox_status "INBOX" + +# vim: set filetype=sh : diff --git a/tests/auth-sasl-plain/interimap.remote b/tests/auth-sasl-plain/interimap.remote new file mode 100644 index 0000000..9c0a623 --- /dev/null +++ b/tests/auth-sasl-plain/interimap.remote @@ -0,0 +1,4 @@ +type = imap +host = localhost +port = 10143 +STARTTLS = NO diff --git a/tests/auth-sasl-plain/remote.conf b/tests/auth-sasl-plain/remote.conf new file mode 100644 index 0000000..3ccbd42 --- /dev/null +++ b/tests/auth-sasl-plain/remote.conf @@ -0,0 +1 @@ +!include conf.d/imapd.conf diff --git a/tests/auth-sasl-plain/t b/tests/auth-sasl-plain/t new file mode 100644 index 0000000..68f71a9 --- /dev/null +++ b/tests/auth-sasl-plain/t @@ -0,0 +1,12 @@ +for ((i = 0; i < 32; i++)); do + u="$(shuf -n1 -e "local" "remote")" + sample_message | deliver -u "$u" +done + +# check that credentials aren't leaked to the debug output +interimap --debug || error +grep -Fx "remote: C: xxx AUTHENTICATE PLAIN [REDACTED]" <"$STDERR" || error + +check_mailbox_status "INBOX" + +# vim: set filetype=sh : diff --git a/tests/compress/interimap.remote b/tests/compress/interimap.remote new file mode 120000 index 0000000..a4ea3f3 --- /dev/null +++ b/tests/compress/interimap.remote @@ -0,0 +1 @@ +../auth-sasl-plain/interimap.remote
\ No newline at end of file diff --git a/tests/compress/remote.conf b/tests/compress/remote.conf new file mode 120000 index 0000000..dbbb908 --- /dev/null +++ b/tests/compress/remote.conf @@ -0,0 +1 @@ +../auth-sasl-plain/remote.conf
\ No newline at end of file diff --git a/tests/compress/t b/tests/compress/t new file mode 100644 index 0000000..5625761 --- /dev/null +++ b/tests/compress/t @@ -0,0 +1,19 @@ +for ((i = 0; i < 32; i++)); do + u="$(shuf -n1 -e "local" "remote")" + sample_message | deliver -u "$u" +done + +# compression enabled by default +interimap --debug || error +grep -Fx "remote: C: 000001 COMPRESS DEFLATE" <"$STDERR" || error +grep -E "^remote: S: 000001 OK( |$)" <"$STDERR" || error + +check_mailbox_status "INBOX" + + +# can be disabled +echo "compress = no" >>"$XDG_CONFIG_HOME/interimap/config" +interimap --debug || error +! grep -E "^remote: C: [^[:blank:]]+ COMPRESS DEFLATE$" <"$STDERR" || error + +# vim: set filetype=sh : diff --git a/tests/condstore/t b/tests/condstore/t new file mode 100644 index 0000000..d4da50f --- /dev/null +++ b/tests/condstore/t @@ -0,0 +1,50 @@ +TIMEOUT=60 +N=4096 + +# test CONDSTORE/QRESYNC (behavior) in UID STORE commands, in particular +# the UNCHANGEDSINCE test: populate, keep assiging keywords at random, +# and make sure interimap is able to reconciliate the changes + +# populate (with dummy messages to speed things up) only one server +# before initializing interimap, so UIDs concide with sequence numbers +# and are identical on both servers +for ((i = 0; i < N; i++)); do + deliver -u "local" <<< . +done + +interimap_init + +# assign a set of 16 tags; not more because in order to maximize the +# likelyhood of conflicts we want UID STORE commands to use large sets +declare -a FLAGS=(0 1 2 3 4 5 6 7 8 9 a b c d e f) + +# start a long-lived interimap process +interimap --watch=1 & PID=$! +trap "ptree_abort $PID" EXIT INT TERM + +timer=$(( $(date +%s) + TIMEOUT )) +while [ $(date +%s) -le $timer ]; do + a="$(shuf -n1 -e "add" "remove" "replace")" + u="$(shuf -n1 -e "local" "remote")" + f="$(shuf -n1 -e "${FLAGS[@]}")" + seqs="$(shuf -n$((N/8)) -i1-$N)" # trigger changes on 1/8 of all messages + doveadm -u "$u" flags "$a" "$f" mailbox "INBOX" "${seqs//$'\n'/,}" + sleep "0.0$(shuf -n1 -i10-99)" # 10 to 99ms +done +sleep 2 + +ptree_abort $PID +trap - EXIT INT TERM + +# make sure the list of uids for a given tag match +flagged_uids() { + local u="$1" f="$2" + doveadm -u "$u" search mailbox "INBOX" keyword "$f" | cut -d" " -f2 | sort -n +} +for f in "${FLAGS[@]}"; do + diff --label="local/$f" --label="remote/$f" -u -- \ + <(flagged_uids "local" "$f") <(flagged_uids "remote" "$f") || + error "UID list differs for keyword '$f'" +done + +# vim: set filetype=sh : diff --git a/tests/db-exclusive-lock/t b/tests/db-exclusive-lock/t new file mode 100644 index 0000000..88172c9 --- /dev/null +++ b/tests/db-exclusive-lock/t @@ -0,0 +1,16 @@ +interimap_init + +# start a background process +interimap --watch=60 & +trap "ptree_abort $!" EXIT INT TERM + +# wait a short while so we have time to lock the database (ugly and racy...) +sleep .5 + +# subsequent runs fail as we can't acquire the exclusive lock +! interimap || error + +grep -Fx "DBD::SQLite::db do failed: database is locked at ./interimap line 177." <"$STDERR" \ + || error "Is \$DBH->do(\"PRAGMA locking_mode = EXCLUSIVE\"); at line 177?" + +# vim: set filetype=sh : diff --git a/tests/db-migration-0-1-foreign-key-violation/t b/tests/db-migration-0-1-foreign-key-violation/t new file mode 100644 index 0000000..35e5be5 --- /dev/null +++ b/tests/db-migration-0-1-foreign-key-violation/t @@ -0,0 +1,21 @@ +interimap_init +grep -Fx "database: Created mailbox INBOX" <"$STDERR" || error "INBOX missing from DB" + +# empty table `mailboxes` and revert its schema to version 0 +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <<-EOF + PRAGMA foreign_keys = OFF; + PRAGMA user_version = 0; + DROP TABLE mailboxes; + CREATE TABLE mailboxes ( + idx INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + mailbox TEXT NOT NULL CHECK (mailbox != '') UNIQUE, + subscribed BOOLEAN NOT NULL + ); +EOF + +# now migration must fail due to broken referential integrity +! interimap || error +grep -Fx "Upgrading database version from 0" <"$STDERR" || error "DB upgrade not attempted" +grep -Fx "database: ERROR: Broken referential integrity! Refusing to commit changes." <"$STDERR" || error "DB upgrade successful despite broken refint" + +# vim: set filetype=sh : diff --git a/tests/db-no-create--watch/t b/tests/db-no-create--watch/t new file mode 100644 index 0000000..89f1e3e --- /dev/null +++ b/tests/db-no-create--watch/t @@ -0,0 +1,6 @@ +! interimap --watch=60 || error + +grep -Ex "DBI connect\(.*\) failed: unable to open database file at \./interimap line 173\." <"$STDERR" || error +test \! -e "$XDG_DATA_HOME/interimap/remote.db" || error + +# vim: set filetype=sh : diff --git a/tests/db-upgrade-0-1-delim-mismatch/before.sql b/tests/db-upgrade-0-1-delim-mismatch/before.sql new file mode 120000 index 0000000..6c31715 --- /dev/null +++ b/tests/db-upgrade-0-1-delim-mismatch/before.sql @@ -0,0 +1 @@ +../db-upgrade-0-1/before.sql
\ No newline at end of file diff --git a/tests/db-upgrade-0-1-delim-mismatch/local.conf b/tests/db-upgrade-0-1-delim-mismatch/local.conf new file mode 100644 index 0000000..900c73f --- /dev/null +++ b/tests/db-upgrade-0-1-delim-mismatch/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = "\"" +} diff --git a/tests/db-upgrade-0-1-delim-mismatch/remote.conf b/tests/db-upgrade-0-1-delim-mismatch/remote.conf new file mode 100644 index 0000000..2d08a24 --- /dev/null +++ b/tests/db-upgrade-0-1-delim-mismatch/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ^ +} diff --git a/tests/db-upgrade-0-1-delim-mismatch/t b/tests/db-upgrade-0-1-delim-mismatch/t new file mode 100644 index 0000000..d133437 --- /dev/null +++ b/tests/db-upgrade-0-1-delim-mismatch/t @@ -0,0 +1,7 @@ +# import an existing non-migrated database +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <"$TESTDIR/before.sql" || error "Couldn't import DB" +! interimap || error + +grep -Fx 'ERROR: Local and remote hierachy delimiters differ (local "\"", remote "^"), refusing to update table `mailboxes`.' <"$STDERR" || error + +# vim: set filetype=sh : diff --git a/tests/00-db-migration-0-to-1/after.sql b/tests/db-upgrade-0-1/after.sql index 18b0ad7..18b0ad7 100644 --- a/tests/00-db-migration-0-to-1/after.sql +++ b/tests/db-upgrade-0-1/after.sql diff --git a/tests/00-db-migration-0-to-1/before.sql b/tests/db-upgrade-0-1/before.sql index 333a1dc..333a1dc 100644 --- a/tests/00-db-migration-0-to-1/before.sql +++ b/tests/db-upgrade-0-1/before.sql diff --git a/tests/db-upgrade-0-1/local.conf b/tests/db-upgrade-0-1/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/db-upgrade-0-1/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/db-upgrade-0-1/remote.conf b/tests/db-upgrade-0-1/remote.conf new file mode 120000 index 0000000..b798ff5 --- /dev/null +++ b/tests/db-upgrade-0-1/remote.conf @@ -0,0 +1 @@ +local.conf
\ No newline at end of file diff --git a/tests/00-db-migration-0-to-1/run b/tests/db-upgrade-0-1/t index 757fe04..088008e 100644 --- a/tests/00-db-migration-0-to-1/run +++ b/tests/db-upgrade-0-1/t @@ -1,14 +1,14 @@ -# create some mailboxes +# create the mailboxes from the database doveadm -u "local" mailbox create "a.b1.c1" "a.b1.c2" "a.b2.c" "a2" doveadm -u "remote" mailbox create "a.b1.c1" "a.b1.c2" "a.b2.c" "a2" # import an existing non-migrated database -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <"$TESTDIR/before.sql" +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <"$TESTDIR/before.sql" || error "Couldn't import DB" # migrate -interimap +interimap || error "Couldn't upgrade DB" -xgrep -Fx "Upgrading database version from 0" <"$STDERR" +grep -Fx "Upgrading database version from 0" <"$STDERR" || error "Couldn't upgrade DB" check_mailboxes_status "a.b1.c1" "a.b1.c2" "a.b2.c" "a2" # verify that the new schema is as expected @@ -28,6 +28,7 @@ EOF # XXX need 'user_version' PRAGMA in the dump for future migrations # http://sqlite.1065341.n5.nabble.com/dump-command-and-user-version-td101228.html diff -u --label="a/dump.sql" --label="b/dump.sql" \ - "$TMPDIR/dump-expected.sql" "$TMPDIR/dump.sql" + "$TMPDIR/dump-expected.sql" "$TMPDIR/dump.sql" \ + || error "DB dumps differ" # vim: set filetype=sh : diff --git a/tests/delete/local.conf b/tests/delete/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/delete/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/delete/remote.conf b/tests/delete/remote.conf new file mode 100644 index 0000000..2d08a24 --- /dev/null +++ b/tests/delete/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ^ +} diff --git a/tests/02-delete/run b/tests/delete/t index f63c52c..c38d4d3 100644 --- a/tests/02-delete/run +++ b/tests/delete/t @@ -4,15 +4,16 @@ for m in "foo.bar" "foo.bar.baz" "INBOX"; do sample_message | deliver -u "local" -- -m "$m" done -interimap +interimap_init check_mailbox_list check_mailboxes_status "foo.bar" "foo.bar.baz" "INBOX" sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump.sql" <<-EOF .dump EOF -# delete non-existent mailbox is a no-op -interimap --target="local,remote" --target="database" --delete "nonexistent" + +step_start "nonexistent source (no-op)" +interimap --target="local,remote" --target="database" --delete "nonexistent" || error check_mailbox_list check_mailboxes_status "foo.bar" "foo.bar.baz" "INBOX" @@ -20,13 +21,22 @@ sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump2.sql" <<-EOF .dump EOF diff -u --label="a/dump.sql" --label="b/dump.sql" \ - "$TMPDIR/dump.sql" "$TMPDIR/dump2.sql" + "$TMPDIR/dump.sql" "$TMPDIR/dump2.sql" || error "SQL dumps differ" +step_done + # foo.bar will become \NoSelect in local, per RFC 3501: "It is permitted # to delete a name that has inferior hierarchical names and does not # have the \Noselect mailbox name attribute. In this case, all messages # in that mailbox are removed, and the name will acquire the \Noselect # mailbox name attribute." +step_start "mailbox with inferiors" +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes.sql" <<-EOF + SELECT idx, mailbox FROM mailboxes + WHERE mailbox != x'$(printf "%s\\0%s" "foo" "bar" | xxd -ps)' + ORDER BY idx +EOF + interimap --target="local" --delete "foo.bar" check_mailbox_list @@ -35,33 +45,51 @@ check_mailboxes_status "foo.bar.baz" "INBOX" sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump2.sql" <<-EOF .dump EOF -diff -u --label="a/dump.sql" --label="b/dump.sql" "$TMPDIR/dump.sql" "$TMPDIR/dump2.sql" +diff -u --label="a/dump.sql" --label="b/dump.sql" \ + "$TMPDIR/dump.sql" "$TMPDIR/dump2.sql" || error "SQL dumps differ" ! doveadm -u "local" mailbox status uidvalidity "foo.bar" # gone doveadm -u "remote" mailbox status uidvalidity "foo^bar" -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes.csv" <<-EOF - SELECT idx, mailbox - FROM mailboxes - WHERE mailbox != x'$(printf "%s\\0%s" "foo" "bar" | xxd -ps)' -EOF - - # now delete from the remote server and the database interimap --delete "foo.bar" ! doveadm -u "local" mailbox status uidvalidity "foo.bar" ! doveadm -u "remote" mailbox status uidvalidity "foo^bar" -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes2.csv" <<-EOF - SELECT idx, mailbox - FROM mailboxes - WHERE mailbox != x'$(printf "%s\\0%s" "foo" "bar" | xxd -ps)' +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes2.sql" <<-EOF + SELECT idx, mailbox FROM mailboxes ORDER BY idx EOF -diff -u --label="a/mailboxes.csv" --label="b/mailboxes.csv" \ - "$TMPDIR/mailboxes.csv" "$TMPDIR/mailboxes2.csv" +diff -u --label="a/mailboxes.sql" --label="b/mailboxes.sql" \ + "$TMPDIR/mailboxes.sql" "$TMPDIR/mailboxes2.sql" || error "SQL dumps differ" check_mailbox_list check_mailboxes_status "foo.bar.baz" "INBOX" +step_done + + +step_start "INBOX (fail)" +! interimap --delete "InBoX" || error "deleted INBOX" +grep -Fx "ERROR: INBOX can't be deleted" <"$STDERR" || error + +check_mailbox_list +check_mailboxes_status "foo.bar.baz" "INBOX" +step_done + + +step_start "\\Noinferiors mailbox" +interimap --delete "foo.bar.baz" + +! doveadm -u "local" mailbox status uidvalidity "foo.bar.baz" +! doveadm -u "remote" mailbox status uidvalidity "foo^bar^baz" + +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/count" <<-EOF + SELECT COUNT(*) FROM mailboxes +EOF +[ "$(< "$TMPDIR/count" )" -eq 1 ] || error "Not only INBOX left?" + +check_mailbox_list +check_mailboxes_status "INBOX" +step_done # vim: set filetype=sh : diff --git a/tests/ignore-mailbox/interimap.conf b/tests/ignore-mailbox/interimap.conf new file mode 100644 index 0000000..6168958 --- /dev/null +++ b/tests/ignore-mailbox/interimap.conf @@ -0,0 +1 @@ +ignore-mailbox = ^virtual(?:\x00|$) diff --git a/tests/ignore-mailbox/local.conf b/tests/ignore-mailbox/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/ignore-mailbox/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/ignore-mailbox/remote.conf b/tests/ignore-mailbox/remote.conf new file mode 100644 index 0000000..2d08a24 --- /dev/null +++ b/tests/ignore-mailbox/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ^ +} diff --git a/tests/ignore-mailbox/t b/tests/ignore-mailbox/t new file mode 100644 index 0000000..f90227c --- /dev/null +++ b/tests/ignore-mailbox/t @@ -0,0 +1,62 @@ +doveadm -u "local" mailbox create "foo" -- "-virtual" +doveadm -u "remote" mailbox create "bar" -- "virtual-" + +interimap_init +check_mailbox_list + +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes.sql" <<-EOF + SELECT idx, mailbox FROM mailboxes ORDER BY idx +EOF + +for ((i = 0; i < 16; i++)); do + u="$(shuf -n1 -e "local" "remote")" # choose target at random + m="$(shuf -n1 -e -- "INBOX" "foo" "bar")" + sample_message | deliver -u "$u" -- -m "$m" +done + +# create new mailboxes matching 'ignore-mailbox' +doveadm -u "local" mailbox create "virtual" "virtual.foo" +doveadm -u "remote" mailbox create "virtual^bar" +for n in $(seq 1 "$(shuf -n1 -i1-8)"); do + sample_message | deliver -u "local" -- -m "virtual" + sample_message | deliver -u "local" -- -m "virtual.foo" +done +for n in $(seq 1 "$(shuf -n1 -i1-8)"); do + sample_message | deliver -u "remote" -- -m "virtual^bar" +done + + +# no new mailbox should be created +interimap || error + +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes2.sql" <<-EOF + SELECT idx, mailbox FROM mailboxes ORDER BY idx +EOF +diff -u --label="a/mailboxes.sql" --label="b/mailboxes.sql" \ + "$TMPDIR/mailboxes.sql" "$TMPDIR/mailboxes2.sql" || error "SQL dumps differ" + +check_mailboxes_status "INBOX" "foo" "bar" + +# double check the unsubscribed mailboxes weren't copied +! doveadm -u "remote" mailbox status uidvalidity "virtual" || error +! doveadm -u "remote" mailbox status uidvalidity "virtual^foo" || error +! doveadm -u "local" mailbox status uidvalidity "virtual.bar" || error + + +# ignored mailboxes are created when passed to the command line +interimap "virtual" "virtual.bar" || error +grep -Fx "database: Created mailbox virtual" <"$STDERR" || error +grep -Fx "database: Created mailbox virtual.bar" <"$STDERR" || error +grep -Fx "local: Created mailbox virtual.bar" <"$STDERR" || error +grep -Fx "remote: Created mailbox virtual" <"$STDERR" || error + +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes.sql" <<-EOF + SELECT idx, mailbox FROM mailboxes + WHERE mailbox != x'$(printf "virtual" | xxd -ps)' + AND mailbox != x'$(printf "%s\\0%s" "virtual" "foo" | xxd -ps)' + ORDER BY idx +EOF + +check_mailboxes_status "virtual" "virtual.bar" || error + +# vim: set filetype=sh : diff --git a/tests/06-largeint/run b/tests/largeint/t index b08bcfa..b0877d5 100644 --- a/tests/06-largeint/run +++ b/tests/largeint/t @@ -12,13 +12,14 @@ doveadm -u "remote" mailbox update --uid-validity 2147483647 "bar" # 2^31-1 doveadm -u "remote" mailbox update --uid-validity 1 "baz" # run() { - local u m - for u in local remote; do - for m in "INBOX" "foo" "bar" "baz"; do - sample_message | deliver -u "$u" -- -m "$m" - done + local u m i + for ((i = 0; i < 64; i++)); do + u="$(shuf -n1 -e "local" "remote")" # choose target at random + m="$(shuf -n1 -e -- "INBOX" "foo" "bar" "baz")" + sample_message | deliver -u "$u" -- -m "$m" done - interimap + interimap || error + check_mailbox_list check_mailbox_status "INBOX" "foo" "bar" "baz" } run diff --git a/tests/list b/tests/list new file mode 100644 index 0000000..52417c1 --- /dev/null +++ b/tests/list @@ -0,0 +1,60 @@ +db-no-create--watch `interimap --watch` refuses to create the database +db-exclusive-lock mutually exclusive DB access + +. DB schema upgrade (v0 -> v1) + db-upgrade-0-1 migrate + # may happen if the server(s) software or its configuration changed + db-upgrade-0-1-delim-mismatch abort on hierarchy delimiter mismatch + # foreign key checking was broken until v0.5 + db-migration-0-1-foreign-key-violation abort on foreign key contraint violation + +. Mailbox deletion + ... delete + +. Mailbox renaming + rename-exists-db abort if target exists in the DB + rename-exists-local abort if target exists locally + rename-exists-remote abort if target exists remotely + ... rename-simple + ... rename-inferiors + +# try values beyond the signed integer limit +largeint Large UIDVALIDITY/UIDNEXT/HIGHESTMODSEQ values + +. Mailbox synchronization + ... sync-mailbox-list + list-reference list-reference + list-mailbox list-mailbox = foo "foo bar" "f\\\"o\x21o.*" "f\0o\0o" + list-select-opts list-select-opts = SUBSCRIBED + ignore-mailbox ignore-mailbox = ^virtual(?:\x00|$) + +resume Resume when aborted +repair --repair + +. Authentication + auth-sasl-plain AUTHENTICATE (SASL PLAIN) + auth-sasl-plain-no-ir AUTHENTICATE (SASL PLAIN, no SASL-IR) + auth-login LOGIN + auth-logindisabled LOGINDISABLED + auth-noplaintext abort when STARTTLS is not offered + +compress COMPRESS=DEFLATE +condstore CONDSTORE +split-set Split large sets to avoid extra-long command lines + +. SSL/TLS + starttls-logindisabled LOGINDISABLED STARTTLS + starttls STARTTLS + tls SSL/TLS handshake + ... tls-verify-peer + tls-pin-fingerprint pubkey fingerprint pinning + tls-protocols force TLS protocol versions + +. Live synchronization (60s) + sync-live local/remote simulation + sync-live-crippled local/remote simulation (crippled remote) + sync-live-tls local/remote simulation (TLS remote) + sync-live-multi local/remote1+remote2+remote3 simulation (3 local namespaces) + +. pullimap + ... pullimap diff --git a/tests/list-mailbox/interimap.conf b/tests/list-mailbox/interimap.conf new file mode 100644 index 0000000..6702107 --- /dev/null +++ b/tests/list-mailbox/interimap.conf @@ -0,0 +1 @@ +list-mailbox = foo "foo bar" "f\\\"o\x21o.*" "f\0o\0o" diff --git a/tests/list-mailbox/local.conf b/tests/list-mailbox/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/list-mailbox/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/list-mailbox/remote.conf b/tests/list-mailbox/remote.conf new file mode 100644 index 0000000..2d6b9e0 --- /dev/null +++ b/tests/list-mailbox/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ? +} diff --git a/tests/list-mailbox/t b/tests/list-mailbox/t new file mode 100644 index 0000000..e905537 --- /dev/null +++ b/tests/list-mailbox/t @@ -0,0 +1,57 @@ +# create and populate some mailboxes locally +declare -a MAILBOXES=( "foo" "foo bar" "f\\\"o!o.bar" "f.o.o" ) +doveadm -u "local" mailbox create -- "${MAILBOXES[@]}" "foobad" "baz" "INBOX" +for ((i = 0; i < 32; i++)); do + m="$(shuf -n1 -e -- "${MAILBOXES[@]}" "foobad" "baz" "INBOX")" + sample_message | deliver -u "local" -- -m "$m" +done + +interimap_init +for m in "${MAILBOXES[@]}"; do + grep -Fx "remote: Created mailbox ${m//./?}" <"$STDERR" || error "${m//./?}" + grep -Fx "database: Created mailbox $m" <"$STDERR" || error +done + +# also check inferiors in the list, but exclude "foobad" and "baz" +check_mailbox_list "${MAILBOXES[@]}" "INBOX" "f\\\"o!o" "f" "f.o" +check_mailboxes_status "${MAILBOXES[@]}" || error + +# double check that "foobad" and "baz" weren't created +! doveadm -u "remote" mailbox status uidvalidity "foobad" || error +! doveadm -u "remote" mailbox status uidvalidity "baz" || error + +# check that "foobad" and "INBOX" aren't in the database +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/count" <<-EOF + SELECT COUNT(*) + FROM mailboxes + WHERE mailbox = x'$(printf "%s" "foobad" | xxd -u -ps)' + OR mailbox = x'$(printf "%s" "INBOX" | xxd -u -ps)' + OR mailbox = x'$(printf "%s" "baz" | xxd -u -ps)' +EOF +[ $(< "$TMPDIR/count") -eq 0 ] || error + + +# mailbox given on the command line overrides list-mailbox +sample_message | deliver -u "local" -- -m "foobad" +sample_message | deliver -u "local" -- -m "foo" +interimap "foobad" || error +! grep -F "remote(foo): Added 1 UID(s)" <"$STDERR" || error +check_mailbox_list "foobad" +check_mailbox_status "foobad" + +interimap "foo" || error +grep -F "remote(foo): Added 1 UID(s)" <"$STDERR" || error +check_mailbox_status "foo" +! check_mailbox_list "baz" + + +# finally, try a bunch of invalid 'list-mailbox' values to test the parser: +# empty string, missing space between values, unterminated string +for v in '""' '"f o o""bar"' '"f o o" "bar" "baz\" x'; do + sed -ri "s/^(list-mailbox\\s*=\\s*).*/\\1${v//\\/\\\\}/" \ + "$XDG_CONFIG_HOME/interimap/config" + ! interimap || error + grep -xF "Invalid value for list-mailbox: $v" <"$STDERR" +done + +# vim: set filetype=sh : diff --git a/tests/list-reference/interimap.local b/tests/list-reference/interimap.local new file mode 100644 index 0000000..a013813 --- /dev/null +++ b/tests/list-reference/interimap.local @@ -0,0 +1 @@ +list-reference = foo/ diff --git a/tests/list-reference/interimap.remote b/tests/list-reference/interimap.remote new file mode 100644 index 0000000..f34119c --- /dev/null +++ b/tests/list-reference/interimap.remote @@ -0,0 +1 @@ +list-reference = bar\ diff --git a/tests/list-reference/local.conf b/tests/list-reference/local.conf new file mode 100644 index 0000000..93e4860 --- /dev/null +++ b/tests/list-reference/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = / +} diff --git a/tests/list-reference/remote.conf b/tests/list-reference/remote.conf new file mode 100644 index 0000000..9657e89 --- /dev/null +++ b/tests/list-reference/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = "\\" +} diff --git a/tests/list-reference/t b/tests/list-reference/t new file mode 100644 index 0000000..a2cc9c7 --- /dev/null +++ b/tests/list-reference/t @@ -0,0 +1,47 @@ +# create and populate some mailboxes in and out the respective list references +doveadm -u "local" mailbox create "foo" "foobar" "foo/bar/baz" "foo/baz" "bar" "bar/baz" +doveadm -u "remote" mailbox create "foo" "foobaz" "foo/baz" "foo\\baz" "bar\\baz" "bar\\!" + +populate() { + local i + for ((i = 0; i < 32; i++)); do + m="$(shuf -n1 -e -- "foo" "foobar" "foo/bar/baz" "foo/baz" "bar" "bar/baz")" + sample_message | deliver -u "local" -- -m "$m" + + m="$(shuf -n1 -e -- "foo" "foobar" "foo/baz" "foo\\baz" "bar\\baz" "bar\\!")" + sample_message | deliver -u "remote" -- -m "$m" + done +} +populate + +interimap_init +grep -Fx "database: Created mailbox bar/baz" <"$STDERR" || error +grep -Fx "database: Created mailbox baz" <"$STDERR" || error +grep -Fx "database: Created mailbox !" <"$STDERR" || error +grep -Fx "local: Created mailbox foo/!" <"$STDERR" || error +grep -Fx "remote: Created mailbox bar\\bar\\baz" <"$STDERR" || error + +verify() { + # check that the mailbox lists match + diff -u --label="local/mailboxes" --label="remote/mailboxes" \ + <( doveadm -u "local" mailbox list | sed -n 's,^foo/,,p' | sort ) \ + <( doveadm -u "remote" mailbox list | sed -n 's,^bar\\,,p' | tr '\\' '/' | sort ) \ + || error "mailbox lists differ" + + for m in "bar/baz" "baz" "!"; do + blob="x'$(printf "%s" "$m" | tr "/" "\\0" | xxd -c256 -u -ps)'" + check_mailbox_status2 "$blob" "foo/$m" "remote" "bar\\${m//\//\\}" + done +} +verify + +# add more messages and re-check +populate +interimap || error +verify + +# double check that mailboxes outside references weren't created +! doveadm -u "local" mailbox status uidvalidity "foobaz" || error +! doveadm -u "remote" mailbox status uidvalidity "foobar" || error + +# vim: set filetype=sh : diff --git a/tests/list-select-opts/interimap.conf b/tests/list-select-opts/interimap.conf new file mode 100644 index 0000000..2fa632d --- /dev/null +++ b/tests/list-select-opts/interimap.conf @@ -0,0 +1 @@ +list-select-opts = SUBSCRIBED diff --git a/tests/list-select-opts/local.conf b/tests/list-select-opts/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/list-select-opts/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/list-select-opts/remote.conf b/tests/list-select-opts/remote.conf new file mode 100644 index 0000000..2d08a24 --- /dev/null +++ b/tests/list-select-opts/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ^ +} diff --git a/tests/list-select-opts/t b/tests/list-select-opts/t new file mode 100644 index 0000000..98acb43 --- /dev/null +++ b/tests/list-select-opts/t @@ -0,0 +1,56 @@ +doveadm -u "local" mailbox create -s "INBOX" "foo.bar" +doveadm -u "remote" mailbox create -s "INBOX" "bar" + +interimap_init +check_mailbox_list + +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes.sql" <<-EOF + SELECT idx, mailbox FROM mailboxes ORDER BY idx +EOF + +for ((i = 0; i < 16; i++)); do + u="$(shuf -n1 -e "local" "remote")" # choose target at random + m="$(shuf -n1 -e -- "INBOX" "foo.bar" "bar")" + sample_message | deliver -u "$u" -- -m "$m" +done + +# create new unsubscribed mailboxes +doveadm -u "local" mailbox create "foo" +doveadm -u "remote" mailbox create "baz" + +for ((i = 0; i < 8; i++)); do + u="$(shuf -n1 -e "local" "remote")" # choose target at random + [ u="local" ] && m="foo" || m="baz" + sample_message | deliver -u "$u" -- -m "$m" +done + + +# no new mailbox should be created +interimap || error + +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes2.sql" <<-EOF + SELECT idx, mailbox FROM mailboxes ORDER BY idx +EOF +diff -u --label="a/mailboxes.sql" --label="b/mailboxes.sql" \ + "$TMPDIR/mailboxes.sql" "$TMPDIR/mailboxes2.sql" || error "SQL dumps differ" + +check_mailboxes_status "INBOX" "foo.bar" "bar" + +# double check the unsubscribed mailboxes weren't copied +! doveadm -u "remote" mailbox status uidvalidity "foo" || error +! doveadm -u "local" mailbox status uidvalidity "baz" || error + +# reconcile when subcribed +doveadm -u "local" mailbox subscribe "foo" +doveadm -u "remote" mailbox subscribe "baz" + +interimap || error +grep -Fx "database: Created mailbox foo" <"$STDERR" || error +grep -Fx "database: Created mailbox baz" <"$STDERR" || error +grep -Fx "local: Created mailbox baz" <"$STDERR" || error +grep -Fx "remote: Created mailbox foo" <"$STDERR" || error + +check_mailbox_list +check_mailboxes_status "INBOX" "foo" "foo.bar" "bar" "baz" + +# vim: set filetype=sh : diff --git a/tests/pullimap/interimap.remote b/tests/pullimap/interimap.remote new file mode 120000 index 0000000..daf3741 --- /dev/null +++ b/tests/pullimap/interimap.remote @@ -0,0 +1 @@ +../tls/interimap.remote
\ No newline at end of file diff --git a/tests/pullimap/local.conf b/tests/pullimap/local.conf new file mode 100644 index 0000000..b67641f --- /dev/null +++ b/tests/pullimap/local.conf @@ -0,0 +1 @@ +!include conf.d/lmtpd.conf diff --git a/tests/pullimap/pullimap.conf b/tests/pullimap/pullimap.conf new file mode 100644 index 0000000..3f6c2e1 --- /dev/null +++ b/tests/pullimap/pullimap.conf @@ -0,0 +1 @@ +deliver-method = lmtp:[127.0.0.1]:10024 diff --git a/tests/pullimap/remote.conf b/tests/pullimap/remote.conf new file mode 120000 index 0000000..6029749 --- /dev/null +++ b/tests/pullimap/remote.conf @@ -0,0 +1 @@ +../tls/remote.conf
\ No newline at end of file diff --git a/tests/pullimap/t b/tests/pullimap/t new file mode 100644 index 0000000..7ae0c5f --- /dev/null +++ b/tests/pullimap/t @@ -0,0 +1,96 @@ +MAILBOX="INBOX" +TIMEOUT=60 +N=2048 + +step_start "\`pullimap --idle\` refuses to create the state file" +! pullimap --idle "remote" || error +step_done + +# make sure remote UIDs are 11-bytes long +doveadm -u "remote" mailbox update --min-next-uid 1000000000 "$MAILBOX" + +# compare mailboxes; can't compare the RFC 3501 TEXT as LMTP adds a +# Received: header. +# TODO unset lmtp_add_received_header once avaisable in Sid: +# https://doc.dovecot.org/settings/dovecot_core_settings/#lmtp-add-received-header +list_mails_sha256() { + local u="$1" guid uid + while read guid uid; do + doveadm -u "$u" -f "flow" fetch body mailbox-guid "$guid" uid "$uid" \ + | sed "1s/body=//" | sha256sum + done < <(doveadm -u "$u" search mailbox "$MAILBOX") | sort -f +} +check() { + diff -u --label="local/mails" --label="remote/mails" \ + <( list_mails_sha256 "local" ) \ + <( list_mails_sha256 "remote" ) \ + || error "mailboxes differ" +} + + +# Add some messages and sync +step_start "Fetching messages" +for ((i = 0; i < 32; i++)); do + sample_message | deliver -u "remote" -- -m "$MAILBOX" +done + +pullimap "remote" || error +check + +# same thing, but with some missing messages +for ((i = 0; i < N; i+=2)); do + sample_message | deliver -u "remote" -- -m "$MAILBOX" + deliver -u "remote" -- -m "$MAILBOX" </dev/null # even seqnum +done +for ((i = 0; i < N; i+=2)); do + # expunge every other message + doveadm -u "remote" expunge mailbox "$MAILBOX" $((N-i+32)) + sample_message | deliver -u "remote" -- -m "$MAILBOX" +done + +pullimap "remote" || error +check + +# count unseen remote messages +doveadm -u "remote" search mailbox "$MAILBOX" unseen >"$TMPDIR/unseen" +[ ! -s "$TMPDIR/unseen" ] || error "\\Unseen messages left" +step_done + + +step_start "--idle (${TIMEOUT}s)" + +pullimap --idle "remote" & PID=$! +trap "ptree_abort $PID" EXIT INT TERM + +timer=$(( $(date +%s) + TIMEOUT )) +while [ $(date +%s) -le $timer ]; do + n="$(shuf -n1 -i1-5)" + for (( i=0; i < n; i++)); do + sample_message | deliver -u "remote" -- -m "$MAILBOX" + done + + s=$(shuf -n1 -i1-1500) + [ $s -ge 1000 ] && s="$(printf "1.%03d" $((s-1000)))" || s="$(printf "0.%03d" $s)" + sleep "$s" +done + +sleep 2 +ptree_abort $PID +trap - EXIT INT TERM + +check +step_done + + +step_start "Purging" +echo "purge-after = 0" >>"$XDG_CONFIG_HOME/pullimap/config" +for ((i = 0; i < 32; i++)); do + sample_message | deliver -u "remote" -- -m "$MAILBOX" +done +pullimap "remote" + +doveadm -u "remote" search mailbox "$MAILBOX" all >"$TMPDIR/messages" +[ ! -s "$TMPDIR/messages" ] || error "messages left" +step_done + +# vim: set filetype=sh : diff --git a/tests/rename-exists-db/local.conf b/tests/rename-exists-db/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/rename-exists-db/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/rename-exists-db/remote.conf b/tests/rename-exists-db/remote.conf new file mode 100644 index 0000000..9657e89 --- /dev/null +++ b/tests/rename-exists-db/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = "\\" +} diff --git a/tests/01-rename-exists-db/run b/tests/rename-exists-db/t index aad7c44..cb6cfcd 100644 --- a/tests/01-rename-exists-db/run +++ b/tests/rename-exists-db/t @@ -1,14 +1,14 @@ doveadm -u "local" mailbox create "root.from" "root.from.child" "t.o" doveadm -u "remote" mailbox create "root\\from" "root\\from\\child" "t\\o" -interimap +interimap_init check_mailbox_list # delete a mailbox on both servers but leave it in the database, then try to use it as target for --rename doveadm -u "local" mailbox delete "t.o" doveadm -u "remote" mailbox delete "t\\o" -! interimap --rename "root.from" "t.o" -xgrep -Fx 'database: ERROR: Mailbox t.o exists. Run `interimap --target=database --delete t.o` to delete.' <"$STDERR" +! interimap --rename "root.from" "t.o" || error +grep -Fx 'database: ERROR: Mailbox t.o exists. Run `interimap --target=database --delete t.o` to delete.' <"$STDERR" || error # vim: set filetype=sh : diff --git a/tests/rename-exists-local/local.conf b/tests/rename-exists-local/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/rename-exists-local/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/rename-exists-local/remote.conf b/tests/rename-exists-local/remote.conf new file mode 100644 index 0000000..9657e89 --- /dev/null +++ b/tests/rename-exists-local/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = "\\" +} diff --git a/tests/01-rename-exists-local/run b/tests/rename-exists-local/t index d82a0a4..190f49a 100644 --- a/tests/01-rename-exists-local/run +++ b/tests/rename-exists-local/t @@ -1,13 +1,13 @@ doveadm -u "local" mailbox create "root.from" "root.from.child" "t.o" doveadm -u "remote" mailbox create "root\\from" "root\\from\\child" -interimap +interimap_init check_mailbox_list # delete a mailbox on the remote server, then try to use it as target for --rename doveadm -u "remote" mailbox delete "t\\o" -! interimap --rename "root.from" "t.o" -xgrep -Fx 'local: ERROR: Mailbox t.o exists. Run `interimap --target=local --delete t.o` to delete.' <"$STDERR" +! interimap --rename "root.from" "t.o" || error +grep -Fx 'local: ERROR: Mailbox t.o exists. Run `interimap --target=local --delete t.o` to delete.' <"$STDERR" || error # vim: set filetype=sh : diff --git a/tests/rename-exists-remote/local.conf b/tests/rename-exists-remote/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/rename-exists-remote/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/rename-exists-remote/remote.conf b/tests/rename-exists-remote/remote.conf new file mode 100644 index 0000000..9657e89 --- /dev/null +++ b/tests/rename-exists-remote/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = "\\" +} diff --git a/tests/01-rename-exists-remote/run b/tests/rename-exists-remote/t index 28af1fc..be16a12 100644 --- a/tests/01-rename-exists-remote/run +++ b/tests/rename-exists-remote/t @@ -1,13 +1,13 @@ doveadm -u "local" mailbox create "root.from" "root.from.child" "t.o" doveadm -u "remote" mailbox create "root\\from" "root\\from\\child" "t\\o" -interimap +interimap_init check_mailbox_list # delete a mailbox on the local server, then try to use it as target for --rename doveadm -u "local" mailbox delete "t.o" -! interimap --rename "root.from" "t.o" -xgrep -Fx 'remote: ERROR: Mailbox t\o exists. Run `interimap --target=remote --delete t.o` to delete.' <"$STDERR" +! interimap --rename "root.from" "t.o" || error +grep -Fx 'remote: ERROR: Mailbox t\o exists. Run `interimap --target=remote --delete t.o` to delete.' <"$STDERR" || remote # vim: set filetype=sh : diff --git a/tests/rename-inferiors/local.conf b/tests/rename-inferiors/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/rename-inferiors/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/rename-inferiors/remote.conf b/tests/rename-inferiors/remote.conf new file mode 100644 index 0000000..2d08a24 --- /dev/null +++ b/tests/rename-inferiors/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ^ +} diff --git a/tests/01-rename/run b/tests/rename-inferiors/t index 6541c5c..9267e6f 100644 --- a/tests/01-rename/run +++ b/tests/rename-inferiors/t @@ -8,7 +8,7 @@ for m in "root^sibbling" "root^sibbling^grandchild" "root2" "INBOX"; do sample_message | deliver -u "remote" -- -m "$m" done -interimap +interimap_init check_mailboxes_status "root.from" "root.from.child" "root.from.child2" "root.from.child.grandchild" \ "root.sibbling" "root.sibbling.grandchild" "root2" "INBOX" sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes.csv" <<-EOF @@ -18,26 +18,31 @@ sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes.csv" <<-EOF ORDER BY idx EOF -# renaming a non-existent mailbox doesn't yield an error -interimap --rename "nonexistent" "nonexistent2" +step_start "non-existent source (no-op)" +interimap --rename "nonexistent" "root" || error "Renamed non-existent mailbox?" +check_mailbox_list +step_done + +step_start "\\NonExistent target (fail)" +! interimap --rename "root2" "root" || error "Didn't abort on ALREADYEXISTS" +grep -E "^local: ERROR: Couldn't rename mailbox root2: NO \[ALREADYEXISTS\] " <"$STDERR" check_mailbox_list +step_done -# renaming to an existing name yields an error -! interimap --rename "root2" "root" -xgrep -E "^local: ERROR: Couldn't rename mailbox root2: NO \[ALREADYEXISTS\] .*" <"$STDERR" # rename 'root.from' to 'from.root', including inferiors +step_start "existing source with inferiors" interimap --rename "root.from" "from.root" -xgrep -Fx 'local: Renamed mailbox root.from to from.root' <"$STDERR" -xgrep -Fx 'remote: Renamed mailbox root^from to from^root' <"$STDERR" -xgrep -Fx 'database: Renamed mailbox root.from to from.root' <"$STDERR" +grep -Fx 'local: Renamed mailbox root.from to from.root' <"$STDERR" +grep -Fx 'remote: Renamed mailbox root^from to from^root' <"$STDERR" +grep -Fx 'database: Renamed mailbox root.from to from.root' <"$STDERR" check_mailbox_list check_mailboxes_status "from.root" "from.root.child" "from.root.child2" "from.root.child.grandchild" \ "root.sibbling" "root.sibbling.grandchild" "root2" "INBOX" before="$(printf "%s\\0%s" "root" "from" | xxd -u -ps)" -after="$(printf "%s\\0%s" "from" "root" | xxd -ps)" +after="$(printf "%s\\0%s" "from" "root" | xxd -u -ps)" sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes2.csv" <<-EOF .mode csv SELECT idx, @@ -50,21 +55,24 @@ sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes2.csv" <<-EOF ORDER BY idx EOF diff -u --label="a/mailboxes.csv" --label="b/mailboxes.csv" \ - "$TMPDIR/mailboxes.csv" "$TMPDIR/mailboxes2.csv" + "$TMPDIR/mailboxes.csv" "$TMPDIR/mailboxes2.csv" \ + || error "Mailbox list differs" +step_done -# Try to rename \NonExistent root and check that its children move +# rename \NonExistent root and check that its children move +step_start "\\NonExistent source with inferiors" interimap --rename "root" "newroot" -xgrep -Fq 'local: Renamed mailbox root to newroot' <"$STDERR" -xgrep -Fq 'remote: Renamed mailbox root to newroot' <"$STDERR" -xgrep -Fq 'database: Renamed mailbox root to newroot' <"$STDERR" +grep -Fq 'local: Renamed mailbox root to newroot' <"$STDERR" +grep -Fq 'remote: Renamed mailbox root to newroot' <"$STDERR" +grep -Fq 'database: Renamed mailbox root to newroot' <"$STDERR" check_mailbox_list check_mailboxes_status "from.root" "from.root.child" "from.root.child2" "from.root.child.grandchild" \ "newroot.sibbling" "newroot.sibbling.grandchild" "root2" "INBOX" before2="$(printf "%s" "root" | xxd -u -ps)" -after2="$(printf "%s" "newroot" | xxd -ps)" +after2="$(printf "%s" "newroot" | xxd -u -ps)" sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes3.csv" <<-EOF .mode csv SELECT idx, @@ -79,6 +87,14 @@ sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes3.csv" <<-EOF ORDER BY idx EOF diff -u --label="a/mailboxes.csv" --label="b/mailboxes.csv" \ - "$TMPDIR/mailboxes2.csv" "$TMPDIR/mailboxes3.csv" + "$TMPDIR/mailboxes2.csv" "$TMPDIR/mailboxes3.csv" \ + || error "Mailbox list differs" +step_done + + +interimap +check_mailbox_list +check_mailboxes_status "from.root" "from.root.child" "from.root.child2" "from.root.child.grandchild" \ + "newroot.sibbling" "newroot.sibbling.grandchild" "root2" "INBOX" # vim: set filetype=sh : diff --git a/tests/rename-simple/t b/tests/rename-simple/t new file mode 100644 index 0000000..6ebee9a --- /dev/null +++ b/tests/rename-simple/t @@ -0,0 +1,61 @@ +doveadm -u "local" mailbox create "foo" + +sample_message | deliver -u "local" -- -m "INBOX" +sample_message | deliver -u "remote" -- -m "INBOX" +sample_message | deliver -u "remote" -- -m "foo" + +interimap_init + +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes.csv" <<-EOF + .mode csv + SELECT idx, hex(mailbox) + FROM mailboxes + ORDER BY idx +EOF + +step_start "non-existent source (no-op)" +interimap --rename "nonexistent" "bar" || error "Rename non-existent mailbox?" +check_mailbox_list +step_done + +step_start "existing target (fail)" +! interimap --rename "nonexistent" "foo" || error "Overwrote target?" +grep -Fx "local: ERROR: Mailbox foo exists. Run \`interimap --target=local --delete foo\` to delete." <"$STDERR" || error +check_mailbox_list +step_done + +step_start "INBOX" +interimap --rename "INBOX" "baz" || error +check_mailbox_list +step_done + +step_start "\\Noinferiors mailbox" +interimap --rename "foo" "bar" || error +check_mailbox_list + +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes2.csv" <<-EOF + .mode csv + SELECT idx, + CASE + WHEN mailbox = x'$(printf "baz" | xxd -u -ps)' + THEN '$(printf "%s" "INBOX" | xxd -u -ps)' + WHEN mailbox = x'$(printf "bar" | xxd -u -ps)' + THEN '$(printf "%s" "foo" | xxd -u -ps)' + ELSE hex(mailbox) + END + FROM mailboxes + ORDER BY idx +EOF +diff -u --label="a/mailboxes.csv" --label="b/mailboxes.csv" \ + "$TMPDIR/mailboxes.csv" "$TMPDIR/mailboxes2.csv" \ + || error "Mailbox list differs" +step_done + +interimap +# recreated after renaming +grep -Fx "database: Created mailbox INBOX" <"$STDERR" + +check_mailbox_list +check_mailboxes_status "INBOX" "bar" "baz" + +# vim: set filetype=sh : diff --git a/tests/repair/local.conf b/tests/repair/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/repair/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/repair/remote.conf b/tests/repair/remote.conf new file mode 100644 index 0000000..1cbbc07 --- /dev/null +++ b/tests/repair/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ~ +} diff --git a/tests/05-repair/run b/tests/repair/t index 66f9ce9..6b205ea 100644 --- a/tests/05-repair/run +++ b/tests/repair/t @@ -9,7 +9,7 @@ for ((i = 0; i < 64; i++)); do sample_message | deliver -u "remote" -- -m "baz" done -interimap +interimap_init check_mailbox_list check_mailboxes_status "foo.bar" "baz" "INBOX" @@ -22,7 +22,7 @@ doveadm -u "remote" expunge mailbox "foo~bar" 4,5,7,10 doveadm -u "local" flags add "\\Answered" mailbox "foo.bar" 2,3,5:7,10 doveadm -u "remote" flags add "\\Seen" mailbox "foo~bar" 4,5,7 -# spoof HIGHESTMODSEQ value in the database, to make it look that we recorded the new changes already +# spoof HIGHESTMODSEQ value in the database to make it look that we recorded the new changes already spoof() { local k="$1" v m hex="$(printf "%s\\0%s" "foo" "bar" | xxd -ps)" shift @@ -46,7 +46,7 @@ doveadm -u "remote" mailbox status "all" "foo~bar" >"$TMPDIR/foo-bar.status.remo # verify that without --repair interimap does nothing due to the spoofed HIGHESTMODSEQ values -interimap "foo.bar" +interimap "foo.bar" || error sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump2.sql" <<-EOF .dump @@ -58,14 +58,14 @@ diff -u --label="a/foo_bar.local" --label="a/foo_bar.local" "$TMPDIR/foo-bar.s diff -u --label="a/foo_bar.remote" --label="a/foo_bar.remote" "$TMPDIR/foo-bar.status.remote" "$TMPDIR/foo-bar.status2.remote" -# deliver more messages and spoof UIDNEXT, on one side only +# deliver more messages and spoof UIDNEXT *on one side only* sample_message | deliver -u "local" -- -m "foo.bar" sample_message | deliver -u "remote" -- -m "foo~bar" spoof UIDNEXT "local" spoof HIGHESTMODSEQ "local" "remote" # now repair -interimap --repair "baz" "foo.bar" +interimap --repair "baz" "foo.bar" || error # 6 updates with \Answered (luid 4,8,11:13,16), 2 of which (luid 12,13) vanished from remote # 3 updates with \Seen (ruid 6,8,10), 1 of which (uid 10) vanished from remote @@ -82,26 +82,26 @@ xcgrep 5 -E '^local\(foo\.bar\): WARNING: UID [0-9]+ disappeared. Redownloading # 6-1 (luid 2 <-> ruid 10 is gone from both) xcgrep 3 -E '^remote\(foo~bar\): WARNING: UID [0-9]+ disappeared. Redownloading local UID [0-9]+\.$' <"$STDERR" -xgrep -E '^local\(baz\): Removed 24 UID\(s\) ' <"$STDERR" -xgrep -E '^remote\(baz\): Removed 5 UID\(s\) ' <"$STDERR" +grep -E '^local\(baz\): Removed 24 UID\(s\) ' <"$STDERR" || error +grep -E '^remote\(baz\): Removed 5 UID\(s\) ' <"$STDERR" || error -# pining UIDs here is not very robust... -xgrep -E '^local\(foo\.bar\): Updated flags \(\\Answered \\Seen\) for UID 16$' <"$STDERR" -xgrep -E '^local\(foo\.bar\): Updated flags \(\\Seen\) for UID 14$' <"$STDERR" -xgrep -E '^remote\(foo~bar\): Updated flags \(\\Answered \\Seen\) for UID 8$' <"$STDERR" -xgrep -E '^remote\(foo~bar\): Updated flags \(\\Answered\) for UID 3,12,16$' <"$STDERR" +# hardcoding UIDs here is not very robust... +grep -E '^local\(foo\.bar\): Updated flags \(\\Answered \\Seen\) for UID 16$' <"$STDERR" || error +grep -E '^local\(foo\.bar\): Updated flags \(\\Seen\) for UID 14$' <"$STDERR" || error +grep -E '^remote\(foo~bar\): Updated flags \(\\Answered \\Seen\) for UID 8$' <"$STDERR" || error +grep -E '^remote\(foo~bar\): Updated flags \(\\Answered\) for UID 3,12,16$' <"$STDERR" || error # luid 17 xcgrep 1 -E '^remote\(foo~bar\): WARNING: No match for modified local UID [0-9]+. Redownloading\.' <"$STDERR" -xgrep -E '^local\(foo\.bar\): Added 5 UID\(s\) ' <"$STDERR" -xgrep -E '^remote\(foo~bar\): Added 4 UID\(s\) ' <"$STDERR" -xgrep -E '^local\(foo\.bar\): Added 1 UID\(s\) ' <"$STDERR" # the new message +grep -E '^local\(foo\.bar\): Added 5 UID\(s\) ' <"$STDERR" || error +grep -E '^remote\(foo~bar\): Added 4 UID\(s\) ' <"$STDERR" || error +grep -E '^local\(foo\.bar\): Added 1 UID\(s\) ' <"$STDERR" || error # the new message check_mailbox_list check_mailboxes_status "baz" "foo.bar" -interimap +interimap || error check_mailboxes_status "baz" "foo.bar" "INBOX" # vim: set filetype=sh : diff --git a/tests/resume/local.conf b/tests/resume/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/resume/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/resume/remote.conf b/tests/resume/remote.conf new file mode 100644 index 0000000..1cbbc07 --- /dev/null +++ b/tests/resume/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ~ +} diff --git a/tests/04-resume/run b/tests/resume/t index 22d66bc..cb0208c 100644 --- a/tests/04-resume/run +++ b/tests/resume/t @@ -5,7 +5,7 @@ for ((i = 0; i < 8; i++)); do sample_message | deliver -u "local" -- -m "foo.bar" sample_message | deliver -u "local" -- -m "INBOX" done -interimap +interimap_init check_mailbox_list check_mailboxes_status "foo" "foo.bar" "baz" "INBOX" @@ -36,9 +36,9 @@ EOF doveadm -u "local" mailbox status "all" "foo" >"$TMPDIR/foo.local" doveadm -u "remote" mailbox status "all" "foo" >"$TMPDIR/foo.remote" -! interimap -xgrep -Fx "Resuming interrupted sync for foo" <"$STDERR" -xgrep -Fx "local(foo): ERROR: UIDVALIDITY changed! ($uidvalidity2 != $uidvalidity) Need to invalidate the UID cache." <"$STDERR" +! interimap || error +grep -Fx "Resuming interrupted sync for foo" <"$STDERR" +grep -Fx "local(foo): ERROR: UIDVALIDITY changed! ($uidvalidity2 != $uidvalidity) Need to invalidate the UID cache." <"$STDERR" sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump2.sql" <<-EOF .dump @@ -70,8 +70,8 @@ sample_message | deliver -u "remote" -- -m "foo~bar" sample_message | deliver -u "local" -- -m "baz" interimap "foo.bar" "InBoX" "baz" # ignore "foo" -xgrep -Fx "Resuming interrupted sync for foo.bar" <"$STDERR" -xgrep -Fx "Resuming interrupted sync for INBOX" <"$STDERR" +grep -Fx "Resuming interrupted sync for foo.bar" <"$STDERR" +grep -Fx "Resuming interrupted sync for INBOX" <"$STDERR" check_mailbox_list check_mailboxes_status "foo.bar" "INBOX" "baz" # ignore "foo" @@ -22,27 +22,39 @@ set -ue PATH=/usr/bin:/bin export PATH -if [ $# -ne 1 ]; then - printf "Usage: %s TESTNAME\\n" "$0" >&2 +if [ $# -eq 0 ] || [ $# -gt 2 ]; then + printf "Usage: %s TESTFILE [TESTNAME]\\n" "$0" >&2 exit 1 fi -TEST="${1%/}" -TEST="${TEST##*/}" -NAME="${TEST#[0-9]*-}" -TESTDIR="$(dirname -- "$0")/$TEST" +BASEDIR="$(dirname -- "$0")" +TESTDIR="$BASEDIR/$1" +TESTNAME="${2-$1}" if [ ! -d "$TESTDIR" ]; then printf "ERROR: Not a directory: %s\\n" "$TESTDIR" >&2 exit 1 fi -ROOTDIR="$(mktemp --tmpdir="${TMPDIR:-/dev/shm}" --directory "$NAME.XXXXXXXXXX")" -trap 'rm -rf -- "$ROOTDIR"' EXIT INT TERM +ROOTDIR="$(mktemp --tmpdir="${TMPDIR:-/dev/shm}" --directory "$1.XXXXXXXXXX")" +declare -a DOVECOT_SERVER=() +trap cleanup EXIT INT TERM +cleanup() { + local pid c + for c in "${DOVECOT_SERVER[@]}"; do + if [ ! -f "$c" ] || ! env -i PATH="/usr/bin:/bin" doveadm -c "$c" stop; then + pid="$(< "${c%/*}/run/master.pid")" + kill -TERM "$pid" || printf "kill(1) exited with status %d\\n" "$?" >&2 + fi + done + rm -rf -- "$ROOTDIR" +} -STDOUT="$ROOTDIR/stdout" -STDERR="$ROOTDIR/stderr" +_STDOUT="$ROOTDIR/stdout" +_STDERR="$ROOTDIR/stderr" TMPDIR="$ROOTDIR/tmp" +STDERR="$(mktemp --tmpdir="$ROOTDIR" "stderr.XXXXXXXXXX")" mkdir -- "$TMPDIR" "$ROOTDIR/home" +declare -a REMOTES=() # Set environment for the given user environ_set() { @@ -60,65 +72,151 @@ environ_set() { # Prepare the test harness prepare() { declare -a ENVIRON=() - local src cfg target u home + local src cfg target u home n proto + if [ -f "$TESTDIR/remotes" ] || [ -L "$TESTDIR/remotes" ]; then + for cfg in $(seq 1 "$(< "$TESTDIR/remotes")"); do + REMOTES+=( "remote$cfg" ) + done + else + REMOTES+=( "remote" ) + fi # copy dovecot config - for src in "$TESTDIR/local.conf" "$TESTDIR"/remote*.conf; do - [ -r "$src" ] || continue - u="${src#"$TESTDIR/"}" - u="${u%.conf}" - home="$ROOTDIR/home/$u" + for u in "local" "${REMOTES[@]}"; do + home="$ROOTDIR/$u/home" export "HOME_$u"="$home" - mkdir -pm0755 -- "$home/.local/bin" - mkdir -pm0700 -- "$home/.config/dovecot" - cat >"$home/.config/dovecot/config" <<-EOF - log_path = /dev/null - mail_home = $ROOTDIR/home/%u + environ_set "$u" + + mkdir -pm0700 -- "$home/.dovecot" + cat >"$home/.dovecot/config" <<-EOF + log_path = $HOME_local/mail.log + mail_home = $home + mail_location = dbox:~/inbox:LAYOUT=index mailbox_list_index = yes ssl = no + listen = 127.0.0.1, ::1 + namespace inbox { + inbox = yes + } EOF - cat >>"$home/.config/dovecot/config" <"$src" - environ_set "$u" + if [ -f "$TESTDIR/$u.conf" ] || [ -L "$TESTDIR/$u.conf" ]; then + cat >>"$home/.dovecot/config" <"$TESTDIR/$u.conf" + fi + cp -aT -- "$BASEDIR/snippets/dovecot" "$home/.dovecot/conf.d" + + proto="$(env -i "${ENVIRON[@]}" doveconf -c "$home/.dovecot/config" -h protocols)" + if [ -n "$proto" ]; then + cat >>"$home/.dovecot/config" <<-EOF + # https://wiki.dovecot.org/HowTo/Rootless + base_dir = $home/.dovecot/run + default_internal_user = $(id -un) + default_internal_group = $(id -gn) + default_login_user = $(id -un) + + service anvil { + chroot = + } + service imap-login { + chroot = + } + service stats { + chroot = + } + + passdb { + args = scheme=PLAIN username_format=%u $home/.dovecot/users + driver = passwd-file + } + userdb { + args = username_format=%u $home/.dovecot/users + driver = passwd-file + } + EOF + + env -i PATH="/usr/bin:/bin" /usr/sbin/dovecot -c "$home/.dovecot/config" + DOVECOT_SERVER+=( "$home/.dovecot/config" ) + printf "%s:%s:::::\\n" "$u" "$(xxd -l16 -p </dev/urandom)" >"$home/.dovecot/users" + fi + + mkdir -pm0755 -- "$home/.local/bin" cat >"$home/.local/bin/doveadm" <<-EOF #!/bin/sh exec env -i ${ENVIRON[@]@Q} \\ - doveadm -c ${home@Q}/.config/dovecot/config "\$@" + doveadm -c ${home@Q}/.dovecot/config "\$@" EOF chmod +x -- "$home/.local/bin/doveadm" done - # copy interimap config - mkdir -pm0700 -- "$HOME_local/.local/share/interimap" - mkdir -pm0700 -- "$HOME_local/.config/interimap" - for cfg in "$TESTDIR"/remote*.conf; do - cfg="${cfg#"$TESTDIR/remote"}" - cfg="${cfg%.conf}" - u="remote$cfg" + # copy interimap and pullimap configuration + mkdir -pm0700 -- "$HOME_local/.local/share/interimap" "$HOME_local/.local/share/pullimap" + mkdir -pm0700 -- "$HOME_local/.config/interimap" "$HOME_local/.config/pullimap" + echo "deliver-rcpt = local" >>"$HOME_local/.config/pullimap/config" + for u in "${REMOTES[@]}"; do + n="${u#remote}" eval home="\$HOME_$u" - if [ -f "$TESTDIR/interimap.conf" ]; then - cat <"$TESTDIR/interimap.conf" >>"$HOME_local/.config/interimap/config$cfg" - fi - cat >>"$HOME_local/.config/interimap/config$cfg" <<-EOF + + cat >>"$HOME_local/.config/interimap/config$n" <<-EOF database = $u.db - + #logfile = $HOME_local/interimap$n.log + EOF + if [ -f "$TESTDIR/interimap$n.conf" ] || [ -L "$TESTDIR/interimap$n.conf" ]; then + cat <"$TESTDIR/interimap$n.conf" >>"$HOME_local/.config/interimap/config$n" + fi + if [ -f "$TESTDIR/pullimap.conf" ] || [ -L "$TESTDIR/pullimap.conf" ]; then + cat <"$TESTDIR/pullimap.conf" >>"$HOME_local/.config/pullimap/config" + fi + + cat >>"$HOME_local/.config/interimap/config$n" <<-EOF + [local] type = tunnel command = exec ${HOME_local@Q}/.local/bin/doveadm exec imap null-stderr = NO - - [remote] - type = tunnel - command = exec ${home@Q}/.local/bin/doveadm exec imap - null-stderr = NO EOF + if [ -f "$TESTDIR/interimap$n.local" ] || [ -L "$TESTDIR/interimap$n.local" ]; then + cat <"$TESTDIR/interimap$n.local" >>"$HOME_local/.config/interimap/config$n" + fi + + if [ -s "$home/.dovecot/users" ]; then + cat <<-EOF + username = $u + password = $(awk -F: -vu="$u" '$1 == u {print $2}' <"$home/.dovecot/users") + EOF + else + cat <<-EOF + type = tunnel + command = exec ${home@Q}/.local/bin/doveadm exec imap + null-stderr = NO + EOF + fi >"$HOME_local/.$u.conf" + if [ -f "$TESTDIR/interimap$n.remote" ] || [ -L "$TESTDIR/interimap$n.remote" ]; then + cat <"$TESTDIR/interimap$n.remote" >>"$HOME_local/.$u.conf" + fi + + { printf "\\n[remote]\\n"; cat <"$HOME_local/.$u.conf"; } >>"$HOME_local/.config/interimap/config$n" + { printf "\\n[%s]\\n" "$u"; cat <"$HOME_local/.$u.conf"; } >>"$HOME_local/.config/pullimap/config" done } prepare # Wrappers for interimap(1) and doveadm(1) -interimap() { - declare -a ENVIRON=() +interimap() { _interimap_cmd "interimap" "$@"; } +pullimap() { _interimap_cmd "pullimap" "$@"; } +_interimap_cmd() { + declare -a ENVIRON=() r=0 + local script="$1" + shift environ_set "local" - env -i "${ENVIRON[@]}" perl -I./lib -T ./interimap "$@" + env -i "${ENVIRON[@]}" perl -I./lib -T "./$script" "$@" 2> >(tee "$STDERR" >&2) +} +interimap_init() { + local u="${1-remote}" + local db="$XDG_DATA_HOME/interimap/$u.db" + local cfg="config${u#remote}" + + test \! -e "$db" || error "Database already exists" 1 + interimap --config "$cfg" || error "Couldn't initialize interimap" 1 + test -f "$db" || error "Database is still missing" 1 + grep -Fx "Creating new schema in database file $db" <"$STDERR" || error "DB wasn't created" 1 } doveadm() { if [ $# -le 2 ] || [ "$1" != "-u" ]; then @@ -137,8 +235,10 @@ sqlite3() { # Sample (random) message sample_message() { local date="$(date +"%s.%N")" + # also try non-conventional addresses for pullimap + local sender="$(shuf -n1 -e "sender" "first.last" "foo-bar" \"\" "\"x\\\" #&\\\\y\"" )" cat <<-EOF - From: <sender@example.net> + From: <$sender@example.net> To: <recipient@example.net> Date: $(date -R -d@"$date") Message-ID: <$date@example.net> @@ -150,7 +250,7 @@ sample_message() { # Wrapper for dovecot-lda(1) deliver() { - local -a argv + declare -a argv while [ $# -gt 0 ] && [ "$1" != "--" ]; do argv+=( "$1" ) shift @@ -167,36 +267,40 @@ dump_test_result() { local above="<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" local src u home declare -a ENVIRON=() - for src in "$TESTDIR/local.conf" "$TESTDIR"/remote*.conf; do - u="${src#"$TESTDIR/"}" - u="${u%.conf}" + for u in "local" "${REMOTES[@]}"; do environ_set "$u" eval home="\$HOME_$u" printf "%s dovecot configuration:\\n%s\\n" "$u" "$below" - env -i "${ENVIRON[@]}" doveconf -c "$home/.config/dovecot/config" -n + env -i "${ENVIRON[@]}" doveconf -c "$home/.dovecot/config" -n + printf "%s\\n\\n" "$above" + done + + for u in "${REMOTES[@]}"; do + printf "interimap configuration (local <-> $u):\\n%s\\n" "$below" + cat <"$HOME_local/.config/interimap/config${u#remote}" printf "%s\\n\\n" "$above" done - printf "(local) interimap configuration:\\n%s\\n" "$below" - cat <"$HOME_local/.config/interimap/config" + printf "mail.log:\\n%s\\n" "$below" + cat -- "$HOME_local/mail.log" 2>/dev/null || true printf "%s\\n\\n" "$above" - printf "standard output was:\\n%s\\n" "$below" - cat <"$STDOUT" + printf "standard output:\\n%s\\n" "$below" + cat <"$_STDOUT" printf "%s\\n\\n" "$above" - printf "standard error was:\\n%s\\n" "$below" - cat <"$STDERR" + printf "standard error:\\n%s\\n" "$below" + cat <"$_STDERR" printf "%s\\n\\n" "$above" } # Check mailbox consistency between the local/remote server and interimap's database check_mailbox_status() { local mailbox="$1" lns="inbox" lsep lprefix rns="inbox" rsep rprefix - lsep="$(doveconf -c "$HOME_local/.config/dovecot/config" -h "namespace/$lns/separator")" - lprefix="$(doveconf -c "$HOME_local/.config/dovecot/config" -h "namespace/$lns/prefix")" - rsep="$(doveconf -c "$HOME_remote/.config/dovecot/config" -h "namespace/$lns/separator")" - rprefix="$(doveconf -c "$HOME_remote/.config/dovecot/config" -h "namespace/$lns/prefix")" + lsep="$(doveconf -c "$HOME_local/.dovecot/config" -h "namespace/$lns/separator")" + lprefix="$(doveconf -c "$HOME_local/.dovecot/config" -h "namespace/$lns/prefix")" + rsep="$(doveconf -c "$HOME_remote/.dovecot/config" -h "namespace/$lns/separator")" + rprefix="$(doveconf -c "$HOME_remote/.dovecot/config" -h "namespace/$lns/prefix")" local blob="x'$(printf "%s" "$mailbox" | tr "$lsep" "\\0" | xxd -c256 -ps)'" local rmailbox="$(printf "%s" "$mailbox" | tr "$lsep" "$rsep")" @@ -225,7 +329,7 @@ check_mailbox_status2() { WHERE mailbox = $blob EOF ) - check_mailbox_status_values "local" "$lmailbox" $lUIDVALIDITY $lUIDNEXT $lHIGHESTMODSEQ $MESSAGES + check_mailbox_status_values "local" "$lmailbox" $lUIDVALIDITY $lUIDNEXT $lHIGHESTMODSEQ $MESSAGES check_mailbox_status_values "$u" "$rmailbox" $rUIDVALIDITY $rUIDNEXT $rHIGHESTMODSEQ $MESSAGES local a b @@ -268,10 +372,10 @@ check_mailboxes_status() { # Check mailbox list constency between the local and remote servers check_mailbox_list() { local m i lns="inbox" lsep lprefix rns="inbox" rsep rprefix sub= - lsep="$(doveconf -c "$HOME_local/.config/dovecot/config" -h "namespace/$lns/separator")" - lprefix="$(doveconf -c "$HOME_local/.config/dovecot/config" -h "namespace/$lns/prefix")" - rsep="$(doveconf -c "$HOME_remote/.config/dovecot/config" -h "namespace/$lns/separator")" - rprefix="$(doveconf -c "$HOME_remote/.config/dovecot/config" -h "namespace/$lns/prefix")" + lsep="$(doveconf -c "$HOME_local/.dovecot/config" -h "namespace/$lns/separator")" + lprefix="$(doveconf -c "$HOME_local/.dovecot/config" -h "namespace/$lns/prefix")" + rsep="$(doveconf -c "$HOME_remote/.dovecot/config" -h "namespace/$lns/separator")" + rprefix="$(doveconf -c "$HOME_remote/.dovecot/config" -h "namespace/$lns/prefix")" if [ $# -gt 0 ] && [ "$1" = "-s" ]; then sub="-s" shift @@ -304,38 +408,54 @@ check_mailbox_list() { <( printf "%s" "${lmailboxes[*]}" | sort ) <( printf "%s" "${rmailboxes[*]}" | sort ) } -# Wrappers for grep(1) and `grep -C` -xgrep() { - if ! grep -q "$@"; then - printf "\`grep %s\` failed on line %d\\n" "${*@Q}" ${BASH_LINENO[0]} >&2 - exit 1 - fi -} +# Wrapper for `grep -c` xcgrep() { local m="$1" n shift if ! n="$(grep -c "$@")" || [ $m -ne $n ]; then - printf "\`grep -c %s\` failed on line %d: %d != %d\\n" "${*@Q}" ${BASH_LINENO[0]} "$m" "$n" >&2 - exit 1 + error "\`grep -c ${*@Q}\` failed ($m != $n)" 1 fi } +error() { + local err="${1+": $1"}" i=${2-0} + printf "ERROR$err on file %s line %d\\n" "${BASH_SOURCE[i+1]}" ${BASH_LINENO[i]} >&2 + exit 1 +} +ptree_abort() { + local pid + for pid in "$@"; do + # kill a process and its children + pkill -TERM -P "$pid" || printf "pkill(1) exited with status %d\\n" "$?" >&2 + kill -TERM "$pid" || printf "kill(1) exited with status %d\\n" "$?" >&2 + done + wait +} +step_start() { printf "%s%s..." "${INDENT-}" "$1" >&3; } +step_done() { passed >&3; } +failed() { + [ -t 1 ] && printf " \\x1B[1;31mFAILED\\x1B[0m\\n" || echo " FAILED" +} +passed() { + [ -t 1 ] && printf " \\x1B[1;32mPASSED\\x1B[0m\\n" || echo " PASSED" +} # Run test in a sub-shell declare -a ENVIRON=() environ_set "local" -export TMPDIR TESTDIR STDOUT STDERR "${ENVIRON[@]}" -export -f environ_set doveadm interimap sqlite3 sample_message deliver +export TMPDIR TESTDIR STDERR "${ENVIRON[@]}" +export -f environ_set doveadm interimap interimap_init pullimap _interimap_cmd +export -f sqlite3 sample_message deliver ptree_abort step_start step_done passed export -f check_mailbox_status check_mailbox_status_values check_mailbox_status2 -export -f check_mailboxes_status check_mailbox_list xgrep xcgrep -printf "%s..." "$TEST" -if ! bash -ue "$TESTDIR/run" >"$STDOUT" 2>"$STDERR"; then - echo " FAILED" - dump_test_result +export -f check_mailboxes_status check_mailbox_list xcgrep error +[ "$TESTNAME" = "..." ] || printf "%s%s..." "${INDENT-}" "$TESTNAME" +if ! bash -ue "$TESTDIR/t" 3>&1 >"$_STDOUT" 2>"$_STDERR"; then + failed + [ "${QUIET-n}" = "y" ] || dump_test_result exit 1 else - echo " OK" - if grep -Paq "\\x00" -- "$STDOUT" "$STDERR"; then - printf "\\tWarn: binary output (outstanding \\0)!\\n" + [ "$TESTNAME" = "..." ] || passed + if grep -Paq "\\x00" -- "$_STDOUT" "$_STDERR"; then + printf "\\tWARN: binary output (outstanding \\0)!\\n" fi exit 0 fi diff --git a/tests/run-all b/tests/run-all new file mode 100755 index 0000000..1eca50c --- /dev/null +++ b/tests/run-all @@ -0,0 +1,65 @@ +#!/bin/bash + +#---------------------------------------------------------------------- +# Test suite for InterIMAP +# Copyright © 2019 Guilhem Moulin <guilhem@fripost.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +#---------------------------------------------------------------------- + +set -ue +PATH=/usr/bin:/bin +export PATH + +BASEDIR="$(dirname -- "$0")" +RUN="$BASEDIR/run" + +failed=0 + +while IFS="" read -r x; do + if [[ "$x" =~ ^([[:blank:]]*)([^[:blank:]#]+)[[:blank:]]+(.*)$ ]]; then + indent="${BASH_REMATCH[1]}" + t="${BASH_REMATCH[2]}" + desc="${BASH_REMATCH[3]}" + + if [ "$t" = "." ]; then + printf "%s%s:\\n" "$indent" "$desc" + continue + elif [ "$t" = "..." ]; then + t="$desc" + desc="..." + fi + elif [[ "$x" =~ ^([[:blank:]]*)([^[:blank:]#]+)$ ]]; then + indent="${BASH_REMATCH[1]}" + t="${BASH_REMATCH[2]}" + unset desc + else + continue + fi + + if [ ! -d "$BASEDIR/$t" ]; then + printf "WARN: %s does doesn't exist, skipping\\n" "$t" >&2 + continue + fi + + INDENT="$indent" "$RUN" "$t" ${desc+"$desc"} || failed=$(( failed+1 )) +done <"$BASEDIR/list" + +if [ $failed -eq 0 ]; then + printf "All tests passed.\\n" + exit 0 +else + printf "%d test(s) failed.\\n" $failed + exit 1 +fi diff --git a/tests/snippets/dovecot/dhparams.pem b/tests/snippets/dovecot/dhparams.pem new file mode 100644 index 0000000..7734d2a --- /dev/null +++ b/tests/snippets/dovecot/dhparams.pem @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEA0J1dU8erRgIk4bMCBMLezjx32pcQpXrdNgl04dxZVxnJ5Ik2gGhA +uQRbbZhAlHNHtFtp9s4TdQ3Ddrv9SuWXYul8U5BWbcxs4nOtwFU8912SfiuVr/kc +4ok2zQ1hdMODtaqWS2ZKBmwcuk4QM6e7fMEAkuZX+Dtf2u8bG5G9B7OL5LggYtrP +cFVNQDtfhs64D+sUKJLWkgeg5NH6nbf+0Gs5a8v3/urHKvoxdVScGmKzF+LsFsBm +ycQjYeVtA9gLr41mo80rrFysUQqZtNkbdkaXOIA2r9JGTYex1l/XaediR8J94ck9 +dwAe2ubRqWcPjmoLJYQIPKiCbvXuJAd0wwIBAg== +-----END DH PARAMETERS----- diff --git a/tests/snippets/dovecot/dovecot.key b/tests/snippets/dovecot/dovecot.key new file mode 100644 index 0000000..95c9846 --- /dev/null +++ b/tests/snippets/dovecot/dovecot.key @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIGkqkKq69zVeF17S3y2U2HkQWh8z9M/xeblCztkKIfzJoAoGCCqGSM49 +AwEHoUQDQgAE1LLppulKw8KjINrDhOjEd0NTax5iDCds+vpA2PwsvvtGoprNAjQM +zX+40u30N3CE0r591txqohSBQ/X+nvG2ug== +-----END EC PRIVATE KEY----- diff --git a/tests/snippets/dovecot/dovecot.pem b/tests/snippets/dovecot/dovecot.pem new file mode 100644 index 0000000..7e53d90 --- /dev/null +++ b/tests/snippets/dovecot/dovecot.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBkzCCATmgAwIBAgIUQ+3hBMsPJcl59xDDujDDfexurOswCgYIKoZIzj0EAwIw +HzEdMBsGA1UEAwwUSW50ZXJJTUFQIHRlc3Qgc3VpdGUwHhcNMTkxMTEwMTM1NDAw +WhcNMjkxMTA3MTM1NDAwWjAfMR0wGwYDVQQDDBRJbnRlcklNQVAgdGVzdCBzdWl0 +ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABNSy6abpSsPCoyDaw4ToxHdDU2se +YgwnbPr6QNj8LL77RqKazQI0DM1/uNLt9DdwhNK+fdbcaqIUgUP1/p7xtrqjUzBR +MB0GA1UdDgQWBBRlh8nSwyX+VlhwuhV7RKYwvKLyDzAfBgNVHSMEGDAWgBRlh8nS +wyX+VlhwuhV7RKYwvKLyDzAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gA +MEUCIQDK8xPPHTbYW5JnZ1Siy8ChZ6GOu2sRwQu7OgtGYGZRSQIgFKn1oAhnq2Oi +aIPqxjvBPMsK/sjrdI/rNsr2XgaulU4= +-----END CERTIFICATE----- diff --git a/tests/snippets/dovecot/imapd.conf b/tests/snippets/dovecot/imapd.conf new file mode 100644 index 0000000..2b26451 --- /dev/null +++ b/tests/snippets/dovecot/imapd.conf @@ -0,0 +1,19 @@ +protocols = $protocols imap + +mail_plugins = $mail_plugins zlib +protocol imap { + mail_plugins = $mail_plugins imap_zlib +} + +service imap-login { + inet_listener imap { + port = 10143 + } + inet_listener imaps { + port = 10993 + ssl = yes + } +} + +# we should avoid sending command lines that are too long +imap_max_line_length = 8192 diff --git a/tests/snippets/dovecot/interimap-required-capabilities.conf b/tests/snippets/dovecot/interimap-required-capabilities.conf new file mode 100644 index 0000000..10dd8e1 --- /dev/null +++ b/tests/snippets/dovecot/interimap-required-capabilities.conf @@ -0,0 +1,3 @@ +# strict minimum of IMAP capabilities required for interimap to work +# (in particular, no LITERAL+, MULTIAPPEND, COMPRESS=DEFLATE, SASL-IR) +imap_capability = IMAP4rev1 ENABLE UIDPLUS LIST-EXTENDED QRESYNC LIST-STATUS diff --git a/tests/snippets/dovecot/lmtpd.conf b/tests/snippets/dovecot/lmtpd.conf new file mode 100644 index 0000000..6aa8365 --- /dev/null +++ b/tests/snippets/dovecot/lmtpd.conf @@ -0,0 +1,7 @@ +protocols = $protocols lmtp + +service lmtp { + inet_listener lmtp { + port = 10024 + } +} diff --git a/tests/snippets/dovecot/ssl.conf b/tests/snippets/dovecot/ssl.conf new file mode 100644 index 0000000..240f24b --- /dev/null +++ b/tests/snippets/dovecot/ssl.conf @@ -0,0 +1,4 @@ +ssl = required +ssl_cert = <dovecot.pem +ssl_key = <dovecot.key +ssl_dh = <dhparams.pem diff --git a/tests/split-set/interimap.remote b/tests/split-set/interimap.remote new file mode 120000 index 0000000..a4ea3f3 --- /dev/null +++ b/tests/split-set/interimap.remote @@ -0,0 +1 @@ +../auth-sasl-plain/interimap.remote
\ No newline at end of file diff --git a/tests/split-set/remote.conf b/tests/split-set/remote.conf new file mode 120000 index 0000000..dbbb908 --- /dev/null +++ b/tests/split-set/remote.conf @@ -0,0 +1 @@ +../auth-sasl-plain/remote.conf
\ No newline at end of file diff --git a/tests/split-set/t b/tests/split-set/t new file mode 100644 index 0000000..5e8ea52 --- /dev/null +++ b/tests/split-set/t @@ -0,0 +1,43 @@ +N=2048 + +# XXX with COMPRESS=DEFLATE dovecot-imapd 2.3.4 hangs when the command +# line exceeds 'imap_max_line_length' (or 8192, whichever is smaller) +# bytes, instead of returning a tagged BAD response. +# https://dovecot.org/pipermail/dovecot/2019-November/117522.html + +# set UIDNEXT to 10^9 so all uids are 10 chars long, otherwise we'd need +# to add many more messages to obtain large sets +doveadm -u "local" mailbox update --min-next-uid 1000000000 "INBOX" +doveadm -u "remote" mailbox update --min-next-uid 1000000000 "INBOX" + +for ((i = 0; i < N; i++)); do + u="$(shuf -n1 -e "local" "remote")" + sample_message | deliver -u "$u" +done + +interimap_init +check_mailbox_status "INBOX" + +# mark every other message as \Seen on the local server +for ((i = 0; i < N; i+=2)); do + doveadm -u "local" flags add "\\Seen" mailbox "INBOX" $((N-i)) +done + +# send the changes to the remote; this results into an UID STORE set +# representation of size 11*N/2-1, which exceeds $imap_max_line_length +interimap +check_mailbox_status "INBOX" + +# now expunge every other message on the remote server; this results +# into large UID STORE and UID EXPUNGE set representation +for ((i = 0; i < N; i+=2)); do + doveadm -u "local" expunge mailbox "INBOX" $((N-i)) + # add some more messages + u="$(shuf -n1 -e "local" "remote")" + sample_message | deliver -u "$u" +done + +interimap || error +check_mailbox_status "INBOX" + +# vim: set filetype=sh : diff --git a/tests/starttls-logindisabled/interimap.remote b/tests/starttls-logindisabled/interimap.remote new file mode 100644 index 0000000..5d7571d --- /dev/null +++ b/tests/starttls-logindisabled/interimap.remote @@ -0,0 +1,4 @@ +type = imap +host = 127.0.0.1 +port = 10143 +SSL_verify = no diff --git a/tests/starttls-logindisabled/remote.conf b/tests/starttls-logindisabled/remote.conf new file mode 100644 index 0000000..be2d51e --- /dev/null +++ b/tests/starttls-logindisabled/remote.conf @@ -0,0 +1,5 @@ +!include conf.d/imapd.conf +!include conf.d/ssl.conf + +# trick dovecot into treating local connections as insecure +imap_capability = +LOGINDISABLED diff --git a/tests/starttls-logindisabled/t b/tests/starttls-logindisabled/t new file mode 100644 index 0000000..0ac7465 --- /dev/null +++ b/tests/starttls-logindisabled/t @@ -0,0 +1,19 @@ +interimap --debug || true + +# double check the presence of 'LOGINDISABLED' and 'STARTTLS' in the preauth capability list +grep -oE -m1 '^remote: S: \* OK \[CAPABILITY IMAP4rev1( [^]]*)? AUTH=[^]]*\]' <"$STDERR" >"$TMPDIR/capability" + +sed -ri 's/^remote: S: \* OK \[CAPABILITY (.*)\]$/\1/' "$TMPDIR/capability" +tr " " "\\n" <"$TMPDIR/capability" >"$TMPDIR/capabilities" +grep -Fx "IMAP4rev1" <"$TMPDIR/capabilities" || error +grep -Fx "LOGINDISABLED" <"$TMPDIR/capabilities" || error + +# make sure we upgraded the connection and check the capability again +grep -Fx "STARTTLS" <"$TMPDIR/capabilities" || error +grep -Fx "remote: C: 000000 STARTTLS" <"$STDERR" || error +grep -Fx "remote: C: 000001 CAPABILITY" <"$STDERR" || error + +# can't go further as the capability string still has the manually +# enforced 'LOGINDISABLED' + +# vim: set filetype=sh : diff --git a/tests/starttls/interimap.remote b/tests/starttls/interimap.remote new file mode 100644 index 0000000..5d7571d --- /dev/null +++ b/tests/starttls/interimap.remote @@ -0,0 +1,4 @@ +type = imap +host = 127.0.0.1 +port = 10143 +SSL_verify = no diff --git a/tests/starttls/remote.conf b/tests/starttls/remote.conf new file mode 100644 index 0000000..3d07ea9 --- /dev/null +++ b/tests/starttls/remote.conf @@ -0,0 +1,2 @@ +!include conf.d/imapd.conf +!include conf.d/ssl.conf diff --git a/tests/starttls/t b/tests/starttls/t new file mode 100644 index 0000000..99a39c2 --- /dev/null +++ b/tests/starttls/t @@ -0,0 +1,27 @@ +for ((i = 0; i < 32; i++)); do + u="$(shuf -n1 -e "local" "remote")" + sample_message | deliver -u "$u" +done + +interimap --debug || error + +# double check the presence of 'STARTTLS' in the preauth capability list +grep -oE -m1 '^remote: S: \* OK \[CAPABILITY IMAP4rev1( [^]]*)? AUTH=[^]]*\]' <"$STDERR" >"$TMPDIR/capability" + +sed -ri 's/^remote: S: \* OK \[CAPABILITY (.*)\]$/\1/' "$TMPDIR/capability" +tr " " "\\n" <"$TMPDIR/capability" >"$TMPDIR/capabilities" +grep -Fx "IMAP4rev1" <"$TMPDIR/capabilities" || error +grep -Fx "STARTTLS" <"$TMPDIR/capabilities" || error + +# make sure we upgraded the connection and check the capability again +grep -Fx "remote: C: 000000 STARTTLS" <"$STDERR" || error +grep -Fx "remote: C: 000001 CAPABILITY" <"$STDERR" || error + +grep -Fx "remote: Disabling SSL protocols: SSLv3, TLSv1, TLSv1.1" <"$STDERR" || error +grep -Fx "remote: Peer certificate fingerprint: sha256\$35944e3bd3300d3ac310bb497a32cc1eef6931482a587ddbc95343740cdf1323" <"$STDERR" || error +grep "^remote: SSL protocol: TLSv1\.[23] " <"$STDERR" || error +grep "^remote: SSL cipher: " <"$STDERR" || error + +check_mailbox_status "INBOX" + +# vim: set filetype=sh : diff --git a/tests/sync-live-crippled/interimap.remote b/tests/sync-live-crippled/interimap.remote new file mode 120000 index 0000000..a4ea3f3 --- /dev/null +++ b/tests/sync-live-crippled/interimap.remote @@ -0,0 +1 @@ +../auth-sasl-plain/interimap.remote
\ No newline at end of file diff --git a/tests/sync-live-crippled/local.conf b/tests/sync-live-crippled/local.conf new file mode 120000 index 0000000..ad27dd1 --- /dev/null +++ b/tests/sync-live-crippled/local.conf @@ -0,0 +1 @@ +../sync-live/local.conf
\ No newline at end of file diff --git a/tests/sync-live-crippled/remote.conf b/tests/sync-live-crippled/remote.conf new file mode 100644 index 0000000..ee22c5f --- /dev/null +++ b/tests/sync-live-crippled/remote.conf @@ -0,0 +1,6 @@ +namespace inbox { + separator = ^ +} + +!include conf.d/imapd.conf +!include conf.d/interimap-required-capabilities.conf diff --git a/tests/sync-live-crippled/t b/tests/sync-live-crippled/t new file mode 120000 index 0000000..189360e --- /dev/null +++ b/tests/sync-live-crippled/t @@ -0,0 +1 @@ +../sync-live/t
\ No newline at end of file diff --git a/tests/sync-live-multi/interimap1.local b/tests/sync-live-multi/interimap1.local new file mode 100644 index 0000000..a013813 --- /dev/null +++ b/tests/sync-live-multi/interimap1.local @@ -0,0 +1 @@ +list-reference = foo/ diff --git a/tests/sync-live-multi/interimap2.local b/tests/sync-live-multi/interimap2.local new file mode 100644 index 0000000..8f10633 --- /dev/null +++ b/tests/sync-live-multi/interimap2.local @@ -0,0 +1 @@ +list-reference = bar/ diff --git a/tests/sync-live-multi/interimap3.local b/tests/sync-live-multi/interimap3.local new file mode 100644 index 0000000..31dee55 --- /dev/null +++ b/tests/sync-live-multi/interimap3.local @@ -0,0 +1 @@ +list-reference = baz/ diff --git a/tests/07-sync-live-multi/local.conf b/tests/sync-live-multi/local.conf index baae39d..baae39d 100644 --- a/tests/07-sync-live-multi/local.conf +++ b/tests/sync-live-multi/local.conf diff --git a/tests/sync-live-multi/remote1.conf b/tests/sync-live-multi/remote1.conf new file mode 100644 index 0000000..2d08a24 --- /dev/null +++ b/tests/sync-live-multi/remote1.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ^ +} diff --git a/tests/sync-live-multi/remote2.conf b/tests/sync-live-multi/remote2.conf new file mode 100644 index 0000000..9657e89 --- /dev/null +++ b/tests/sync-live-multi/remote2.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = "\\" +} diff --git a/tests/sync-live-multi/remote3.conf b/tests/sync-live-multi/remote3.conf new file mode 100644 index 0000000..0b6aafd --- /dev/null +++ b/tests/sync-live-multi/remote3.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = "?" +} diff --git a/tests/sync-live-multi/remotes b/tests/sync-live-multi/remotes new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/tests/sync-live-multi/remotes @@ -0,0 +1 @@ +3 diff --git a/tests/07-sync-live-multi/run b/tests/sync-live-multi/t index 15a27fd..9b129ec 100644 --- a/tests/07-sync-live-multi/run +++ b/tests/sync-live-multi/t @@ -1,72 +1,59 @@ -# add references to each interimap instance -sed -ri 's#^\[local\]$#&\nlist-reference = foo/#' "$XDG_CONFIG_HOME/interimap/config" -sed -ri 's#^\[local\]$#&\nlist-reference = bar/#' "$XDG_CONFIG_HOME/interimap/config2" -sed -ri 's#^\[local\]$#&\nlist-reference = baz/#' "$XDG_CONFIG_HOME/interimap/config3" - -# create databases -interimap --config="config" -interimap --config="config2" -interimap --config="config3" - -# start long-lived interimap processes -interimap --config="config" --watch=1 & pid=$! -interimap --config="config2" --watch=1 & pid2=$! -interimap --config="config3" --watch=1 & pid3=$! - -abort() { - # kill interimap process and its children - pkill -P "$pid" -TERM || true - kill -TERM "$pid" || true - pkill -P "$pid2" -TERM || true - kill -TERM "$pid2" || true - pkill -P "$pid3" -TERM || true - kill -TERM "$pid3" || true - wait -} -trap abort EXIT INT TERM - +TIMEOUT=60 # mailbox list (as seen on local) and alphabet -declare -a mailboxes=( "INBOX" ) alphabet=() +declare -a MAILBOXES=( "INBOX" ) ALPHABET=() str="#+-0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" for ((i=0; i < ${#str}; i++)); do - alphabet[i]="${str:i:1}" + ALPHABET[i]="${str:i:1}" done -declare -a targets=( "local" "remote" "remote2" "remote3" ) +declare -a TARGETS=( "local" "remote1" "remote2" "remote3" ) + + +# create databases +interimap_init "remote1" +interimap_init "remote2" +interimap_init "remote3" + +# start long-lived interimap processes +declare -a PID=() +trap 'ptree_abort ${PID[@]}' EXIT INT TERM +interimap --config="config1" --watch=1 & PID+=( $! ) +interimap --config="config2" --watch=1 & PID+=( $! ) +interimap --config="config3" --watch=1 & PID+=( $! ) -timer=$(( $(date +%s) + 30 )) +timer=$(( $(date +%s) + TIMEOUT )) while [ $(date +%s) -le $timer ]; do # create new mailbox with 10% probability if [ $(shuf -n1 -i0-9) -eq 0 ]; then - u="$(shuf -n1 -e -- "${targets[@]}")" # choose target at random + u="$(shuf -n1 -e -- "${TARGETS[@]}")" # choose target at random case "$u" in local) ns="$(shuf -n1 -e "foo/" "bar/" "baz/")";; - remote) ns="foo/";; + remote1) ns="foo/";; remote2) ns="bar/";; remote3) ns="baz/";; - *) echo "Uh?" >&2; exit 1;; + *) error "Uh?";; esac m= d=$(shuf -n1 -i1-3) # random depth for (( i=0; i < d; i++)); do l=$(shuf -n1 -i1-16) - m="${m:+$m/}$(shuf -n "$l" -e -- "${alphabet[@]}" | tr -d '\n')" + m="${m:+$m/}$(shuf -n "$l" -e -- "${ALPHABET[@]}" | tr -d '\n')" done - mailboxes+=( "$ns$m" ) + MAILBOXES+=( "$ns$m" ) case "$u" in local) m="$ns$m";; - remote) m="${m//\//^}";; + remote1) m="${m//\//^}";; remote2) m="${m//\//\\}";; remote3) m="${m//\//\?}";; - *) echo "Uh?" >&2; exit 1;; + *) error "Uh?";; esac doveadm -u "$u" mailbox create -- "$m" fi # EXPUNGE some messages - u="$(shuf -n1 -e -- "${targets[@]}")" # choose target at random + u="$(shuf -n1 -e -- "${TARGETS[@]}")" # choose target at random n="$(shuf -n1 -i0-3)" while read guid uid; do doveadm -u "$u" expunge mailbox-guid "$guid" uid "$uid" @@ -74,7 +61,7 @@ while [ $(date +%s) -le $timer ]; do # mark some existing messages as read (toggle \Seen flag as unlike other # flags it's easier to query and check_mailboxes_status checks it) - u="$(shuf -n1 -e -- "${targets[@]}")" # choose target at random + u="$(shuf -n1 -e -- "${TARGETS[@]}")" # choose target at random n="$(shuf -n1 -i0-9)" while read guid uid; do a="$(shuf -n1 -e add remove replace)" @@ -83,14 +70,14 @@ while [ $(date +%s) -le $timer ]; do # select at random a mailbox where to deliver some messages u="$(shuf -n1 -e "local" "remote")" # choose target at random - m="$(shuf -n1 -e -- "${mailboxes[@]}")" + m="$(shuf -n1 -e -- "${MAILBOXES[@]}")" if [ "$u" = "remote" ]; then case "$m" in - foo/*) u="remote"; m="${m#foo/}"; m="${m//\//^}";; + foo/*) u="remote1"; m="${m#foo/}"; m="${m//\//^}";; bar/*) u="remote2"; m="${m#bar/}"; m="${m//\//\\}";; baz/*) u="remote3"; m="${m#baz/}"; m="${m//\//\?}";; - INBOX) u="$(shuf -n1 -e "remote" "remote2" "remote3")";; - *) echo "Uh? $m" >&2; exit 1;; + INBOX) u="$(shuf -n1 -e "remote1" "remote2" "remote3")";; + *) error "Uh? $m";; esac fi @@ -100,8 +87,10 @@ while [ $(date +%s) -le $timer ]; do sample_message | deliver -u "$u" -- -m "$m" done - # sleep a little bit - sleep "$(printf "0.%03d" "$(shuf -n1 -i1-999)")" + # sleep a little bit (sometimes beyond --watch timer, sometimes not) + s=$(shuf -n1 -i1-1500) + [ $s -ge 1000 ] && s="$(printf "1.%03d" $((s-1000)))" || s="$(printf "0.%03d" $s)" + sleep "$s" done # wait a little longer so interimap has time to run loop() again and @@ -109,13 +98,13 @@ done # started above sleep 2 -abort +ptree_abort ${PID[@]} trap - EXIT INT TERM # check that the mailbox lists match -diff -u --label="local/mailboxes" --label="remote/mailboxes" \ - <( doveadm -u "local" mailbox list | sed -n "s,^foo/,,p" | sort ) \ - <( doveadm -u "remote" mailbox list | tr '^' '/' | sort ) +diff -u --label="local/mailboxes" --label="remote1/mailboxes" \ + <( doveadm -u "local" mailbox list | sed -n "s,^foo/,,p" | sort ) \ + <( doveadm -u "remote1" mailbox list | tr '^' '/' | sort ) diff -u --label="local/mailboxes" --label="remote2/mailboxes" \ <( doveadm -u "local" mailbox list | sed -n "s,^bar/,,p" | sort ) \ <( doveadm -u "remote2" mailbox list | tr '\\' '/' | sort ) @@ -123,13 +112,13 @@ diff -u --label="local/mailboxes" --label="remote3/mailboxes" \ <( doveadm -u "local" mailbox list | sed -n "s,^baz/,,p" | sort ) \ <( doveadm -u "remote3" mailbox list | tr '?' '/' | sort ) -for m in "${mailboxes[@]}"; do +for m in "${MAILBOXES[@]}"; do case "$m" in - foo/*) u="remote"; mb="${m#foo/}"; mr="${mb//\//^}";; + foo/*) u="remote1"; mb="${m#foo/}"; mr="${mb//\//^}";; bar/*) u="remote2"; mb="${m#bar/}"; mr="${mb//\//\\}";; baz/*) u="remote3"; mb="${m#baz/}"; mr="${mb//\//\?}";; INBOX) continue;; - *) echo "Uh? $m" >&2; exit 1;; + *) error "Uh? $m";; esac blob="x'$(printf "%s" "$mb" | tr "/" "\\0" | xxd -c256 -ps)'" check_mailbox_status2 "$blob" "$m" "$u" "$mr" diff --git a/tests/sync-live-tls/interimap.remote b/tests/sync-live-tls/interimap.remote new file mode 120000 index 0000000..daf3741 --- /dev/null +++ b/tests/sync-live-tls/interimap.remote @@ -0,0 +1 @@ +../tls/interimap.remote
\ No newline at end of file diff --git a/tests/sync-live-tls/local.conf b/tests/sync-live-tls/local.conf new file mode 120000 index 0000000..ad27dd1 --- /dev/null +++ b/tests/sync-live-tls/local.conf @@ -0,0 +1 @@ +../sync-live/local.conf
\ No newline at end of file diff --git a/tests/sync-live-tls/remote.conf b/tests/sync-live-tls/remote.conf new file mode 100644 index 0000000..b2af2d2 --- /dev/null +++ b/tests/sync-live-tls/remote.conf @@ -0,0 +1,6 @@ +namespace inbox { + separator = ^ +} + +!include conf.d/imapd.conf +!include conf.d/ssl.conf diff --git a/tests/sync-live-tls/t b/tests/sync-live-tls/t new file mode 120000 index 0000000..189360e --- /dev/null +++ b/tests/sync-live-tls/t @@ -0,0 +1 @@ +../sync-live/t
\ No newline at end of file diff --git a/tests/sync-live/local.conf b/tests/sync-live/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/sync-live/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/sync-live/remote.conf b/tests/sync-live/remote.conf new file mode 100644 index 0000000..2d08a24 --- /dev/null +++ b/tests/sync-live/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ^ +} diff --git a/tests/07-sync-live/run b/tests/sync-live/t index 04d8247..19d1e08 100644 --- a/tests/07-sync-live/run +++ b/tests/sync-live/t @@ -1,25 +1,19 @@ -# create database -interimap - -# start a long-lived interimap process -interimap --watch=1 & pid=$! - -abort() { - # kill interimap process and its children - pkill -P "$pid" -TERM || true - kill -TERM "$pid" || true - wait -} -trap abort EXIT INT TERM +TIMEOUT=60 # mailbox list and alphabet (exclude &, / and ~, which dovecot treats specially) -declare -a mailboxes=( "INBOX" ) alphabet=() +declare -a MAILBOXES=( "INBOX" ) ALPHABET=() str="!\"#\$'()+,-0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\[\\\]_\`abcdefghijklmnopqrstuvwxyz{|}" for ((i=0; i < ${#str}; i++)); do - alphabet[i]="${str:i:1}" + ALPHABET[i]="${str:i:1}" done -timer=$(( $(date +%s) + 30 )) +interimap_init + +# start a long-lived interimap process +interimap --watch=1 & PID=$! +trap "ptree_abort $PID" EXIT INT TERM + +timer=$(( $(date +%s) + TIMEOUT )) while [ $(date +%s) -le $timer ]; do # create new mailbox with 10% probability if [ $(shuf -n1 -i0-9) -eq 0 ]; then @@ -27,9 +21,9 @@ while [ $(date +%s) -le $timer ]; do d=$(shuf -n1 -i1-3) # random depth for (( i=0; i < d; i++)); do l=$(shuf -n1 -i1-16) - m="${m:+$m.}$(shuf -n "$l" -e -- "${alphabet[@]}" | tr -d '\n')" + m="${m:+$m.}$(shuf -n "$l" -e -- "${ALPHABET[@]}" | tr -d '\n')" done - mailboxes+=( "$m" ) + MAILBOXES+=( "$m" ) u="$(shuf -n1 -e "local" "remote")" # choose target at random [ "$u" = "local" ] || m="${m//./^}" doveadm -u "$u" mailbox create -- "$m" @@ -53,7 +47,7 @@ while [ $(date +%s) -le $timer ]; do # select at random a mailbox where to deliver some messages u="$(shuf -n1 -e "local" "remote")" # choose target at random - m="$(shuf -n1 -e -- "${mailboxes[@]}")" + m="$(shuf -n1 -e -- "${MAILBOXES[@]}")" [ "$u" = "local" ] || m="${m//./^}" # deliver between 1 and 5 messages to the chosen mailbox @@ -62,8 +56,10 @@ while [ $(date +%s) -le $timer ]; do sample_message | deliver -u "$u" -- -m "$m" done - # sleep a little bit - sleep "$(printf "0.%03d" "$(shuf -n1 -i1-999)")" + # sleep a little bit (sometimes beyond --watch timer, sometimes not) + s=$(shuf -n1 -i1-1500) + [ $s -ge 1000 ] && s="$(printf "1.%03d" $((s-1000)))" || s="$(printf "0.%03d" $s)" + sleep "$s" done # wait a little longer so interimap has time to run loop() again and @@ -71,10 +67,10 @@ done # above sleep 2 -abort +ptree_abort $PID trap - EXIT INT TERM check_mailbox_list -check_mailboxes_status "${mailboxes[@]}" +check_mailboxes_status "${MAILBOXES[@]}" # vim: set filetype=sh : diff --git a/tests/sync-mailbox-list/local.conf b/tests/sync-mailbox-list/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/sync-mailbox-list/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/sync-mailbox-list/remote.conf b/tests/sync-mailbox-list/remote.conf new file mode 100644 index 0000000..1cbbc07 --- /dev/null +++ b/tests/sync-mailbox-list/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ~ +} diff --git a/tests/sync-mailbox-list/t b/tests/sync-mailbox-list/t new file mode 100644 index 0000000..ea80fbf --- /dev/null +++ b/tests/sync-mailbox-list/t @@ -0,0 +1,93 @@ +# pre-create some mailboxes and susbscribe to some +# foo: present on both, subscribed to both +# bar: present on both, subscribed to local only +# baz: present on both, subscribed to remote only +# foo.bar: present on local only +# foo.baz: present on remote only +doveadm -u "local" mailbox create "foo" "bar" "baz" "foo.bar" "fo!o [b*a%r]" +doveadm -u "local" mailbox subscribe "foo" "bar" +doveadm -u "remote" mailbox create "foo" "bar" "baz" "foo~baz" "foo]bar" +doveadm -u "remote" mailbox subscribe "foo" "baz" + +populate() { + local i + for ((i = 0; i < 32; i++)); do + m="$(shuf -n1 -e -- "foo" "bar" "baz" "foo.bar" "fo!o [b*a%r]")" + sample_message | deliver -u "local" -- -m "$m" + + m="$(shuf -n1 -e -- "foo" "bar" "baz" "foo~baz" "foo]bar")" + sample_message | deliver -u "remote" -- -m "$m" + done +} +verify() { + check_mailbox_list || error + check_mailboxes_status "foo" "bar" "baz" "foo.bar" "foo.baz" "INBOX" "fo!o [b*a%r]" "foo]bar" +} +populate + +step_start "pre-subscribtions" +interimap_init +grep -Fx "local: Subscribe to baz" <"$STDERR" || error +grep -Fx "remote: Subscribe to bar" <"$STDERR" || error +grep -Fx "local: Created mailbox foo.baz" <"$STDERR" || error +grep -Fx "remote: Created mailbox foo~bar" <"$STDERR" || error +step_done + +# ensure the mailbox list is synchronized +step_start "mailbox list and content" +verify +check_mailbox_list -s +step_done + + +# delete a mailbox on one server and verify that synchronization fails as it's still in the database +step_start "aborts if present in database" +for u in "local" "remote"; do + [ "$u" = "local" ] && { m="foo.bar"; m2="$m"; } || { m="foo.baz"; m2="foo~baz"; } + + doveadm -u "$u" mailbox delete "$m2" + ! interimap || error + grep -Fx "database: ERROR: Mailbox $m exists. Run \`interimap --target=database --delete $m\` to delete." <"$STDERR" + + interimap --target="database" --delete "$m" || error + grep -Fx "database: Removed mailbox $m" <"$STDERR" || error + + interimap || error # create again + grep -Fx "database: Created mailbox $m" <"$STDERR" || error + grep -Fx "$u: Created mailbox $m2" <"$STDERR" || error +done +verify +check_mailbox_list -s +step_done + + + +# (un)subscribe from some mailboxes, including a non-existent one +step_start "new (un)subscribtions" +doveadm -u "local" mailbox unsubscribe "foo" +doveadm -u "remote" mailbox unsubscribe "bar" +doveadm -u "local" mailbox subscribe "foo.bar" "foo.nonexistent" "foo.baz" +doveadm -u "remote" mailbox subscribe "foo~bar" "bar~nonexistent" +populate + +interimap +grep -Fx "remote: Unsubscribe to foo" <"$STDERR" +grep -Fx "local: Unsubscribe to bar" <"$STDERR" +grep -Fx "remote: Subscribe to foo~baz" <"$STDERR" +verify +check_mailbox_list -s $(doveadm -u "local" mailbox list) # exclude "foo.nonexistent" and "bar~nonexistent" + +# check that "baz", "foo.bar" and "foo.baz" are the only subscribed mailboxes +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/count" <<-EOF + SELECT COUNT(*) + FROM mailboxes + WHERE subscribed <> (mailbox IN ( + x'$(printf "%s" "baz" | xxd -ps)', + x'$(printf "%s\\0%s" "foo" "bar" | xxd -ps)', + x'$(printf "%s\\0%s" "foo" "baz" | xxd -ps)' + )) +EOF +[ $(< "$TMPDIR/count") -eq 0 ] || error +step_done + +# vim: set filetype=sh : diff --git a/tests/tls-pin-fingerprint/interimap.remote b/tests/tls-pin-fingerprint/interimap.remote new file mode 120000 index 0000000..daf3741 --- /dev/null +++ b/tests/tls-pin-fingerprint/interimap.remote @@ -0,0 +1 @@ +../tls/interimap.remote
\ No newline at end of file diff --git a/tests/tls-pin-fingerprint/remote.conf b/tests/tls-pin-fingerprint/remote.conf new file mode 120000 index 0000000..6029749 --- /dev/null +++ b/tests/tls-pin-fingerprint/remote.conf @@ -0,0 +1 @@ +../tls/remote.conf
\ No newline at end of file diff --git a/tests/tls-pin-fingerprint/t b/tests/tls-pin-fingerprint/t new file mode 100644 index 0000000..1b84390 --- /dev/null +++ b/tests/tls-pin-fingerprint/t @@ -0,0 +1,33 @@ +# backup config +install -m0600 "$XDG_CONFIG_HOME/interimap/config" "$XDG_CONFIG_HOME/interimap/config~" +with_remote_config() { + install -m0600 "$XDG_CONFIG_HOME/interimap/config~" "$XDG_CONFIG_HOME/interimap/config" + cat >>"$XDG_CONFIG_HOME/interimap/config" +} + +# pinned valid fingerprint +with_remote_config <<-EOF + SSL_fingerprint = sha256\$e8fc8d03ffe75e03897136a2f1c5647bf8c36be7136a6883a732a8c4961c1614 +EOF + +for ((i = 0; i < 32; i++)); do + u="$(shuf -n1 -e "local" "remote")" + sample_message | deliver -u "$u" +done +interimap_init +check_mailbox_status "INBOX" + + +# and now an invalid one +with_remote_config <<-EOF + SSL_fingerprint = sha256\$deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef +EOF +! interimap --debug || error + +grep -Fx "remote: ERROR: Can't initiate TLS/SSL handshake" <"$STDERR" || error +grep -Fx "remote: WARNING: Fingerprint doesn't match! MiTM in action?" <"$STDERR" || error +grep -Fx "remote: ERROR: Can't initiate TLS/SSL handshake" <"$STDERR" || error +# make sure we didn't send any credentials +! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error + +# vim: set filetype=sh : diff --git a/tests/tls-protocols/interimap.remote b/tests/tls-protocols/interimap.remote new file mode 120000 index 0000000..daf3741 --- /dev/null +++ b/tests/tls-protocols/interimap.remote @@ -0,0 +1 @@ +../tls/interimap.remote
\ No newline at end of file diff --git a/tests/tls-protocols/remote.conf b/tests/tls-protocols/remote.conf new file mode 120000 index 0000000..6029749 --- /dev/null +++ b/tests/tls-protocols/remote.conf @@ -0,0 +1 @@ +../tls/remote.conf
\ No newline at end of file diff --git a/tests/tls-protocols/t b/tests/tls-protocols/t new file mode 100644 index 0000000..f34a95b --- /dev/null +++ b/tests/tls-protocols/t @@ -0,0 +1,39 @@ +# backup config +install -m0600 "$XDG_CONFIG_HOME/interimap/config" "$XDG_CONFIG_HOME/interimap/config~" +with_remote_tls_protocols() { + install -m0600 "$XDG_CONFIG_HOME/interimap/config~" "$XDG_CONFIG_HOME/interimap/config" + printf "SSL_protocols = %s\\n" "$*" >>"$XDG_CONFIG_HOME/interimap/config" +} + +# default +interimap --debug || error +grep -Fx "remote: Disabling SSL protocols: SSLv3, TLSv1, TLSv1.1" <"$STDERR" || error +grep -E "^remote: SSL protocol: TLSv1\.[23] " <"$STDERR" || error + +# also disable TLSv1.2 +with_remote_tls_protocols "!SSLv2" "!SSLv3" "!TLSv1" "!TLSv1.1" "!TLSv1.2" +interimap --debug || error +grep -Fx "remote: Disabling SSL protocols: SSLv3, TLSv1, TLSv1.1, TLSv1.2" <"$STDERR" || error +grep -E "^remote: SSL protocol: TLSv1\.3 " <"$STDERR" || error + +# force TLSv1.2 +with_remote_tls_protocols "TLSv1.2" +interimap --debug || error +grep -Fx "remote: Disabling SSL protocols: SSLv3, TLSv1, TLSv1.1, TLSv1.3" <"$STDERR" || error +grep -E "^remote: SSL protocol: TLSv1\.2 " <"$STDERR" || error + +# force TLSv1 to TLSv1.2 +with_remote_tls_protocols "TLSv1" "TLSv1.1" "TLSv1.2" +interimap --debug || error +grep -Fx "remote: Disabling SSL protocols: SSLv3, TLSv1.3" <"$STDERR" || error +grep -E "^remote: SSL protocol: TLSv(1\.[12])? " <"$STDERR" || error + +# force SSLv2 and SSLv3, fails as it's disabled server side +with_remote_tls_protocols "SSLv2" "SSLv3" +! interimap --debug || error +grep -Fx "remote: Disabling SSL protocols: TLSv1, TLSv1.1, TLSv1.2, TLSv1.3" <"$STDERR" || error +grep -Fx "remote: ERROR: Can't initiate TLS/SSL handshake" <"$STDERR" || error +# make sure we didn't send any credentials +! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error + +# vim: set filetype=sh : diff --git a/tests/tls-verify-peer/interimap.remote b/tests/tls-verify-peer/interimap.remote new file mode 100644 index 0000000..b02fcd0 --- /dev/null +++ b/tests/tls-verify-peer/interimap.remote @@ -0,0 +1,2 @@ +host = ::1 +port = 10993 diff --git a/tests/tls-verify-peer/remote.conf b/tests/tls-verify-peer/remote.conf new file mode 120000 index 0000000..6029749 --- /dev/null +++ b/tests/tls-verify-peer/remote.conf @@ -0,0 +1 @@ +../tls/remote.conf
\ No newline at end of file diff --git a/tests/tls-verify-peer/t b/tests/tls-verify-peer/t new file mode 100644 index 0000000..d84328a --- /dev/null +++ b/tests/tls-verify-peer/t @@ -0,0 +1,80 @@ +CERT=~/.dovecot/conf.d/dovecot.pem + +unverified_peer() { + ! interimap --debug || error + + grep -Fx "remote: ERROR: Can't initiate TLS/SSL handshake" <"$STDERR" || error + sed -nr "s/remote: \[[0-9]+\] (preverify=[0-9]+)$/\1/p" <"$STDERR" >"$TMPDIR/preverify" + [ -s "$TMPDIR/preverify" ] || error + ! grep -Fvx "preverify=0" <"$TMPDIR/preverify" || error + + # make sure we didn't send any credentials + ! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error +} +verified_peer() { + local i u + for ((i = 0; i < 32; i++)); do + u="$(shuf -n1 -e "local" "remote")" + sample_message | deliver -u "$u" + done + interimap --debug || error + + sed -nr "s/remote: \[[0-9]+\] (preverify=[0-9]+)$/\1/p" <"$STDERR" >"$TMPDIR/preverify" + [ -s "$TMPDIR/preverify" ] || error + ! grep -Fvx "preverify=1" <"$TMPDIR/preverify" || error + + grep "^remote: SSL protocol: TLSv1\.[23] " <"$STDERR" || error + grep "^remote: SSL cipher: " <"$STDERR" || error + + check_mailbox_status "INBOX" +} + +# backup config +install -m0600 "$XDG_CONFIG_HOME/interimap/config" "$XDG_CONFIG_HOME/interimap/config~" +with_remote_config() { + install -m0600 "$XDG_CONFIG_HOME/interimap/config~" "$XDG_CONFIG_HOME/interimap/config" + cat >>"$XDG_CONFIG_HOME/interimap/config" +} + +step_start "peer verification enabled by default" +unverified_peer +step_done + +step_start "peer verification result honored when pinned pubkey matches" +pkey_sha256="$(openssl x509 -pubkey <"$CERT" | openssl pkey -pubin -outform DER \ + | openssl dgst -sha256 | sed -rn "/^.*=\\s*/ {s///p;q}")" +with_remote_config <<-EOF + SSL_fingerprint = sha256\$$pkey_sha256 +EOF +unverified_peer +! grep -Fx "remote: WARNING: Fingerprint doesn't match! MiTM in action?" <"$STDERR" || error +step_done + + +step_start "SSL_CAfile" +if [ -f "/etc/ssl/certs/ca-certificates.crt" ]; then + # the self-signed cert should not be in there + with_remote_config <<<"SSL_CAfile = /etc/ssl/certs/ca-certificates.crt" + unverified_peer +fi +with_remote_config <<<"SSL_CAfile = $CERT" +verified_peer +step_done + + +step_start "SSL_CApath" +if [ -d "/etc/ssl/certs" ]; then + # the self-signed cert should not be in there + with_remote_config <<<"SSL_CApath = /etc/ssl/certs" + unverified_peer +fi + +capath=$(mktemp --tmpdir="$TMPDIR" --directory capath.XXXXXX) +cp -t"$capath" "$CERT" +c_rehash "$capath" + +with_remote_config <<<"SSL_CApath = $capath" +verified_peer +step_done + +# vim: set filetype=sh : diff --git a/tests/tls/interimap.remote b/tests/tls/interimap.remote new file mode 100644 index 0000000..2c0e37e --- /dev/null +++ b/tests/tls/interimap.remote @@ -0,0 +1,3 @@ +host = ::1 +port = 10993 +SSL_verify = no diff --git a/tests/tls/remote.conf b/tests/tls/remote.conf new file mode 100644 index 0000000..3d07ea9 --- /dev/null +++ b/tests/tls/remote.conf @@ -0,0 +1,2 @@ +!include conf.d/imapd.conf +!include conf.d/ssl.conf diff --git a/tests/tls/t b/tests/tls/t new file mode 100644 index 0000000..dd6d955 --- /dev/null +++ b/tests/tls/t @@ -0,0 +1,14 @@ +for ((i = 0; i < 32; i++)); do + u="$(shuf -n1 -e "local" "remote")" + sample_message | deliver -u "$u" +done + +interimap --debug || error +grep -Fx "remote: Disabling SSL protocols: SSLv3, TLSv1, TLSv1.1" <"$STDERR" || error +grep -Fx "remote: Peer certificate fingerprint: sha256\$35944e3bd3300d3ac310bb497a32cc1eef6931482a587ddbc95343740cdf1323" <"$STDERR" || error +grep "^remote: SSL protocol: TLSv1\.[23] " <"$STDERR" || error +grep "^remote: SSL cipher: " <"$STDERR" || error + +check_mailbox_status "INBOX" + +# vim: set filetype=sh : |