From 67440844c422ee30b31df9a46a7f99ac0e833add Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sat, 9 Nov 2019 03:13:45 +0100 Subject: Refactor and improve test suite. --- tests/00-db-exclusive/local.conf | 5 - tests/00-db-exclusive/remote.conf | 5 - tests/00-db-exclusive/run | 25 --- .../before.sql | 1 - .../local.conf | 6 - .../remote.conf | 6 - tests/00-db-migration-0-to-1-delim-mismatch/run | 8 - .../local.conf | 6 - .../remote.conf | 6 - .../run | 23 --- tests/00-db-migration-0-to-1/after.sql | 14 -- tests/00-db-migration-0-to-1/before.sql | 14 -- tests/00-db-migration-0-to-1/local.conf | 6 - tests/00-db-migration-0-to-1/remote.conf | 6 - tests/00-db-migration-0-to-1/run | 33 ---- tests/01-rename-exists-db/local.conf | 6 - tests/01-rename-exists-db/remote.conf | 6 - tests/01-rename-exists-db/run | 14 -- tests/01-rename-exists-local/local.conf | 6 - tests/01-rename-exists-local/remote.conf | 6 - tests/01-rename-exists-local/run | 13 -- tests/01-rename-exists-remote/local.conf | 6 - tests/01-rename-exists-remote/remote.conf | 6 - tests/01-rename-exists-remote/run | 13 -- tests/01-rename/local.conf | 6 - tests/01-rename/remote.conf | 6 - tests/01-rename/run | 84 ---------- tests/02-delete/local.conf | 6 - tests/02-delete/remote.conf | 6 - tests/02-delete/run | 67 -------- tests/03-sync-mailbox-list-partial/interimap.conf | 1 - tests/03-sync-mailbox-list-partial/local.conf | 6 - tests/03-sync-mailbox-list-partial/remote.conf | 6 - tests/03-sync-mailbox-list-partial/run | 57 ------- tests/03-sync-mailbox-list-ref/local.conf | 6 - tests/03-sync-mailbox-list-ref/remote.conf | 6 - tests/03-sync-mailbox-list-ref/run | 28 ---- tests/03-sync-mailbox-list/local.conf | 6 - tests/03-sync-mailbox-list/remote.conf | 6 - tests/03-sync-mailbox-list/run | 73 --------- tests/04-resume/local.conf | 6 - tests/04-resume/remote.conf | 6 - tests/04-resume/run | 98 ------------ tests/05-repair/local.conf | 6 - tests/05-repair/remote.conf | 6 - tests/05-repair/run | 107 ------------- tests/06-largeint/local.conf | 5 - tests/06-largeint/remote.conf | 5 - tests/06-largeint/run | 38 ----- tests/07-sync-live-multi/local.conf | 30 ---- tests/07-sync-live-multi/remote.conf | 6 - tests/07-sync-live-multi/remote2.conf | 6 - tests/07-sync-live-multi/remote3.conf | 6 - tests/07-sync-live-multi/run | 138 ---------------- tests/07-sync-live/local.conf | 6 - tests/07-sync-live/remote.conf | 6 - tests/07-sync-live/run | 80 ---------- tests/db-exclusive-lock/t | 16 ++ tests/db-migration-0-1-foreign-key-violation/t | 21 +++ tests/db-no-create--watch/t | 6 + tests/db-upgrade-0-1-delim-mismatch/before.sql | 1 + tests/db-upgrade-0-1-delim-mismatch/local.conf | 3 + tests/db-upgrade-0-1-delim-mismatch/remote.conf | 3 + tests/db-upgrade-0-1-delim-mismatch/t | 7 + tests/db-upgrade-0-1/after.sql | 14 ++ tests/db-upgrade-0-1/before.sql | 14 ++ tests/db-upgrade-0-1/local.conf | 3 + tests/db-upgrade-0-1/remote.conf | 1 + tests/db-upgrade-0-1/t | 34 ++++ tests/delete/local.conf | 3 + tests/delete/remote.conf | 3 + tests/delete/t | 95 +++++++++++ tests/ignore-mailbox/interimap.conf | 1 + tests/ignore-mailbox/local.conf | 3 + tests/ignore-mailbox/remote.conf | 3 + tests/ignore-mailbox/t | 62 ++++++++ tests/largeint/t | 39 +++++ tests/list | 37 +++++ tests/list-mailbox/interimap.conf | 1 + tests/list-mailbox/local.conf | 3 + tests/list-mailbox/remote.conf | 3 + tests/list-mailbox/t | 57 +++++++ tests/list-reference/interimap.local | 1 + tests/list-reference/interimap.remote | 1 + tests/list-reference/local.conf | 3 + tests/list-reference/remote.conf | 3 + tests/list-reference/t | 47 ++++++ tests/list-select-opts/interimap.conf | 1 + tests/list-select-opts/local.conf | 3 + tests/list-select-opts/remote.conf | 3 + tests/list-select-opts/t | 56 +++++++ tests/rename-exists-db/local.conf | 3 + tests/rename-exists-db/remote.conf | 3 + tests/rename-exists-db/t | 14 ++ tests/rename-exists-local/local.conf | 3 + tests/rename-exists-local/remote.conf | 3 + tests/rename-exists-local/t | 13 ++ tests/rename-exists-remote/local.conf | 3 + tests/rename-exists-remote/remote.conf | 3 + tests/rename-exists-remote/t | 13 ++ tests/rename-inferiors/local.conf | 3 + tests/rename-inferiors/remote.conf | 3 + tests/rename-inferiors/t | 100 ++++++++++++ tests/rename-simple/t | 61 ++++++++ tests/repair/local.conf | 3 + tests/repair/remote.conf | 3 + tests/repair/t | 107 +++++++++++++ tests/resume/local.conf | 3 + tests/resume/remote.conf | 3 + tests/resume/t | 98 ++++++++++++ tests/run | 173 ++++++++++++++------- tests/run-all | 65 ++++++++ tests/sync-live-crippled/local.conf | 1 + tests/sync-live-crippled/remote.conf | 6 + tests/sync-live-crippled/t | 1 + tests/sync-live-multi/interimap1.local | 1 + tests/sync-live-multi/interimap2.local | 1 + tests/sync-live-multi/interimap3.local | 1 + tests/sync-live-multi/local.conf | 30 ++++ tests/sync-live-multi/remote1.conf | 3 + tests/sync-live-multi/remote2.conf | 3 + tests/sync-live-multi/remote3.conf | 3 + tests/sync-live-multi/remotes | 1 + tests/sync-live-multi/t | 127 +++++++++++++++ tests/sync-live/local.conf | 3 + tests/sync-live/remote.conf | 3 + tests/sync-live/t | 76 +++++++++ tests/sync-mailbox-list/local.conf | 3 + tests/sync-mailbox-list/remote.conf | 3 + tests/sync-mailbox-list/t | 93 +++++++++++ 130 files changed, 1530 insertions(+), 1225 deletions(-) delete mode 100644 tests/00-db-exclusive/local.conf delete mode 100644 tests/00-db-exclusive/remote.conf delete mode 100644 tests/00-db-exclusive/run delete mode 120000 tests/00-db-migration-0-to-1-delim-mismatch/before.sql delete mode 100644 tests/00-db-migration-0-to-1-delim-mismatch/local.conf delete mode 100644 tests/00-db-migration-0-to-1-delim-mismatch/remote.conf delete mode 100644 tests/00-db-migration-0-to-1-delim-mismatch/run delete mode 100644 tests/00-db-migration-0-to-1-foreign-key-violation/local.conf delete mode 100644 tests/00-db-migration-0-to-1-foreign-key-violation/remote.conf delete mode 100644 tests/00-db-migration-0-to-1-foreign-key-violation/run delete mode 100644 tests/00-db-migration-0-to-1/after.sql delete mode 100644 tests/00-db-migration-0-to-1/before.sql delete mode 100644 tests/00-db-migration-0-to-1/local.conf delete mode 100644 tests/00-db-migration-0-to-1/remote.conf delete mode 100644 tests/00-db-migration-0-to-1/run delete mode 100644 tests/01-rename-exists-db/local.conf delete mode 100644 tests/01-rename-exists-db/remote.conf delete mode 100644 tests/01-rename-exists-db/run delete mode 100644 tests/01-rename-exists-local/local.conf delete mode 100644 tests/01-rename-exists-local/remote.conf delete mode 100644 tests/01-rename-exists-local/run delete mode 100644 tests/01-rename-exists-remote/local.conf delete mode 100644 tests/01-rename-exists-remote/remote.conf delete mode 100644 tests/01-rename-exists-remote/run delete mode 100644 tests/01-rename/local.conf delete mode 100644 tests/01-rename/remote.conf delete mode 100644 tests/01-rename/run delete mode 100644 tests/02-delete/local.conf delete mode 100644 tests/02-delete/remote.conf delete mode 100644 tests/02-delete/run delete mode 100644 tests/03-sync-mailbox-list-partial/interimap.conf delete mode 100644 tests/03-sync-mailbox-list-partial/local.conf delete mode 100644 tests/03-sync-mailbox-list-partial/remote.conf delete mode 100644 tests/03-sync-mailbox-list-partial/run delete mode 100644 tests/03-sync-mailbox-list-ref/local.conf delete mode 100644 tests/03-sync-mailbox-list-ref/remote.conf delete mode 100644 tests/03-sync-mailbox-list-ref/run delete mode 100644 tests/03-sync-mailbox-list/local.conf delete mode 100644 tests/03-sync-mailbox-list/remote.conf delete mode 100644 tests/03-sync-mailbox-list/run delete mode 100644 tests/04-resume/local.conf delete mode 100644 tests/04-resume/remote.conf delete mode 100644 tests/04-resume/run delete mode 100644 tests/05-repair/local.conf delete mode 100644 tests/05-repair/remote.conf delete mode 100644 tests/05-repair/run delete mode 100644 tests/06-largeint/local.conf delete mode 100644 tests/06-largeint/remote.conf delete mode 100644 tests/06-largeint/run delete mode 100644 tests/07-sync-live-multi/local.conf delete mode 100644 tests/07-sync-live-multi/remote.conf delete mode 100644 tests/07-sync-live-multi/remote2.conf delete mode 100644 tests/07-sync-live-multi/remote3.conf delete mode 100644 tests/07-sync-live-multi/run delete mode 100644 tests/07-sync-live/local.conf delete mode 100644 tests/07-sync-live/remote.conf delete mode 100644 tests/07-sync-live/run create mode 100644 tests/db-exclusive-lock/t create mode 100644 tests/db-migration-0-1-foreign-key-violation/t create mode 100644 tests/db-no-create--watch/t create mode 120000 tests/db-upgrade-0-1-delim-mismatch/before.sql create mode 100644 tests/db-upgrade-0-1-delim-mismatch/local.conf create mode 100644 tests/db-upgrade-0-1-delim-mismatch/remote.conf create mode 100644 tests/db-upgrade-0-1-delim-mismatch/t create mode 100644 tests/db-upgrade-0-1/after.sql create mode 100644 tests/db-upgrade-0-1/before.sql create mode 100644 tests/db-upgrade-0-1/local.conf create mode 120000 tests/db-upgrade-0-1/remote.conf create mode 100644 tests/db-upgrade-0-1/t create mode 100644 tests/delete/local.conf create mode 100644 tests/delete/remote.conf create mode 100644 tests/delete/t create mode 100644 tests/ignore-mailbox/interimap.conf create mode 100644 tests/ignore-mailbox/local.conf create mode 100644 tests/ignore-mailbox/remote.conf create mode 100644 tests/ignore-mailbox/t create mode 100644 tests/largeint/t create mode 100644 tests/list create mode 100644 tests/list-mailbox/interimap.conf create mode 100644 tests/list-mailbox/local.conf create mode 100644 tests/list-mailbox/remote.conf create mode 100644 tests/list-mailbox/t create mode 100644 tests/list-reference/interimap.local create mode 100644 tests/list-reference/interimap.remote create mode 100644 tests/list-reference/local.conf create mode 100644 tests/list-reference/remote.conf create mode 100644 tests/list-reference/t create mode 100644 tests/list-select-opts/interimap.conf create mode 100644 tests/list-select-opts/local.conf create mode 100644 tests/list-select-opts/remote.conf create mode 100644 tests/list-select-opts/t create mode 100644 tests/rename-exists-db/local.conf create mode 100644 tests/rename-exists-db/remote.conf create mode 100644 tests/rename-exists-db/t create mode 100644 tests/rename-exists-local/local.conf create mode 100644 tests/rename-exists-local/remote.conf create mode 100644 tests/rename-exists-local/t create mode 100644 tests/rename-exists-remote/local.conf create mode 100644 tests/rename-exists-remote/remote.conf create mode 100644 tests/rename-exists-remote/t create mode 100644 tests/rename-inferiors/local.conf create mode 100644 tests/rename-inferiors/remote.conf create mode 100644 tests/rename-inferiors/t create mode 100644 tests/rename-simple/t create mode 100644 tests/repair/local.conf create mode 100644 tests/repair/remote.conf create mode 100644 tests/repair/t create mode 100644 tests/resume/local.conf create mode 100644 tests/resume/remote.conf create mode 100644 tests/resume/t create mode 100755 tests/run-all create mode 120000 tests/sync-live-crippled/local.conf create mode 100644 tests/sync-live-crippled/remote.conf create mode 120000 tests/sync-live-crippled/t create mode 100644 tests/sync-live-multi/interimap1.local create mode 100644 tests/sync-live-multi/interimap2.local create mode 100644 tests/sync-live-multi/interimap3.local create mode 100644 tests/sync-live-multi/local.conf create mode 100644 tests/sync-live-multi/remote1.conf create mode 100644 tests/sync-live-multi/remote2.conf create mode 100644 tests/sync-live-multi/remote3.conf create mode 100644 tests/sync-live-multi/remotes create mode 100644 tests/sync-live-multi/t create mode 100644 tests/sync-live/local.conf create mode 100644 tests/sync-live/remote.conf create mode 100644 tests/sync-live/t create mode 100644 tests/sync-mailbox-list/local.conf create mode 100644 tests/sync-mailbox-list/remote.conf create mode 100644 tests/sync-mailbox-list/t (limited to 'tests') 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/after.sql b/tests/00-db-migration-0-to-1/after.sql deleted file mode 100644 index 18b0ad7..0000000 --- a/tests/00-db-migration-0-to-1/after.sql +++ /dev/null @@ -1,14 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE local (idx INTEGER NOT NULL PRIMARY KEY REFERENCES mailboxes(idx), UIDVALIDITY UNSIGNED INT NOT NULL CHECK (UIDVALIDITY > 0), UIDNEXT UNSIGNED INT NOT NULL, HIGHESTMODSEQ UNSIGNED BIGINT NOT NULL); -CREATE TABLE remote (idx INTEGER NOT NULL PRIMARY KEY REFERENCES mailboxes(idx), UIDVALIDITY UNSIGNED INT NOT NULL CHECK (UIDVALIDITY > 0), UIDNEXT UNSIGNED INT NOT NULL, HIGHESTMODSEQ UNSIGNED BIGINT NOT NULL); -CREATE TABLE mapping (idx INTEGER NOT NULL REFERENCES mailboxes(idx), lUID UNSIGNED INT NOT NULL CHECK (lUID > 0), rUID UNSIGNED INT NOT NULL CHECK (rUID > 0), PRIMARY KEY (idx,lUID), UNIQUE (idx,rUID)); -CREATE TABLE IF NOT EXISTS "mailboxes" (idx INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, mailbox BLOB COLLATE BINARY NOT NULL CHECK (mailbox != '') UNIQUE, subscribed BOOLEAN NOT NULL); -INSERT INTO mailboxes VALUES(1,X'61006231006332',0); -INSERT INTO mailboxes VALUES(2,X'61006231006331',0); -INSERT INTO mailboxes VALUES(3,X'494e424f58',0); -INSERT INTO mailboxes VALUES(4,X'6132',0); -INSERT INTO mailboxes VALUES(5,X'610062320063',0); -DELETE FROM sqlite_sequence; -INSERT INTO sqlite_sequence VALUES('mailboxes',5); -COMMIT; diff --git a/tests/00-db-migration-0-to-1/before.sql b/tests/00-db-migration-0-to-1/before.sql deleted file mode 100644 index 333a1dc..0000000 --- a/tests/00-db-migration-0-to-1/before.sql +++ /dev/null @@ -1,14 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE mailboxes (idx INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, mailbox TEXT NOT NULL CHECK (mailbox != '') UNIQUE, subscribed BOOLEAN NOT NULL); -INSERT INTO mailboxes VALUES(1,'a.b1.c2',0); -INSERT INTO mailboxes VALUES(2,'a.b1.c1',0); -INSERT INTO mailboxes VALUES(3,'INBOX',0); -INSERT INTO mailboxes VALUES(4,'a2',0); -INSERT INTO mailboxes VALUES(5,'a.b2.c',0); -CREATE TABLE local (idx INTEGER NOT NULL PRIMARY KEY REFERENCES mailboxes(idx), UIDVALIDITY UNSIGNED INT NOT NULL CHECK (UIDVALIDITY > 0), UIDNEXT UNSIGNED INT NOT NULL, HIGHESTMODSEQ UNSIGNED BIGINT NOT NULL); -CREATE TABLE remote (idx INTEGER NOT NULL PRIMARY KEY REFERENCES mailboxes(idx), UIDVALIDITY UNSIGNED INT NOT NULL CHECK (UIDVALIDITY > 0), UIDNEXT UNSIGNED INT NOT NULL, HIGHESTMODSEQ UNSIGNED BIGINT NOT NULL); -CREATE TABLE mapping (idx INTEGER NOT NULL REFERENCES mailboxes(idx), lUID UNSIGNED INT NOT NULL CHECK (lUID > 0), rUID UNSIGNED INT NOT NULL CHECK (rUID > 0), PRIMARY KEY (idx,lUID), UNIQUE (idx,rUID)); -DELETE FROM sqlite_sequence; -INSERT INTO sqlite_sequence VALUES('mailboxes',5); -COMMIT; 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/00-db-migration-0-to-1/run b/tests/00-db-migration-0-to-1/run deleted file mode 100644 index 757fe04..0000000 --- a/tests/00-db-migration-0-to-1/run +++ /dev/null @@ -1,33 +0,0 @@ -# create some mailboxes -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" - -# migrate -interimap - -xgrep -Fx "Upgrading database version from 0" <"$STDERR" -check_mailboxes_status "a.b1.c1" "a.b1.c2" "a.b2.c" "a2" - -# verify that the new schema is as expected -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump.sql" <<-EOF - DELETE FROM local; - DELETE FROM remote; - .dump -EOF - -# re-import and dump the expected dump to work around SQLite format -# differences across versions -sqlite3 "$XDG_DATA_HOME/interimap/remote2.db" <"$TESTDIR/after.sql" -sqlite3 "$XDG_DATA_HOME/interimap/remote2.db" >"$TMPDIR/dump-expected.sql" <<-EOF - .dump -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" - -# vim: set filetype=sh : 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-db/run b/tests/01-rename-exists-db/run deleted file mode 100644 index aad7c44..0000000 --- a/tests/01-rename-exists-db/run +++ /dev/null @@ -1,14 +0,0 @@ -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 -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" - -# vim: set filetype=sh : 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-local/run b/tests/01-rename-exists-local/run deleted file mode 100644 index d82a0a4..0000000 --- a/tests/01-rename-exists-local/run +++ /dev/null @@ -1,13 +0,0 @@ -doveadm -u "local" mailbox create "root.from" "root.from.child" "t.o" -doveadm -u "remote" mailbox create "root\\from" "root\\from\\child" - -interimap -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" - -# vim: set filetype=sh : 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-exists-remote/run b/tests/01-rename-exists-remote/run deleted file mode 100644 index 28af1fc..0000000 --- a/tests/01-rename-exists-remote/run +++ /dev/null @@ -1,13 +0,0 @@ -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 -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" - -# vim: set filetype=sh : 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/01-rename/run b/tests/01-rename/run deleted file mode 100644 index 6541c5c..0000000 --- a/tests/01-rename/run +++ /dev/null @@ -1,84 +0,0 @@ -doveadm -u "local" mailbox create "root.from" "root.from.child" "root.from.child2" "root.from.child.grandchild" -doveadm -u "remote" mailbox create "root^sibbling" "root^sibbling^grandchild" "root2" - -for m in "root.from" "root.from.child" "root.from.child2" "root.from.child.grandchild" "INBOX"; do - sample_message | deliver -u "local" -- -m "$m" -done -for m in "root^sibbling" "root^sibbling^grandchild" "root2" "INBOX"; do - sample_message | deliver -u "remote" -- -m "$m" -done - -interimap -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 - .mode csv - SELECT idx, hex(mailbox) - FROM mailboxes - ORDER BY idx -EOF - -# renaming a non-existent mailbox doesn't yield an error -interimap --rename "nonexistent" "nonexistent2" -check_mailbox_list - -# 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 -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" - -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)" -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes2.csv" <<-EOF - .mode csv - SELECT idx, - CASE - WHEN mailbox = x'$after' OR hex(mailbox) LIKE '${after}00%' - THEN '$before' || SUBSTR(hex(mailbox), $((${#after}+1))) - 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" - - -# Try to rename \NonExistent root and check that its children move -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" - -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)" -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes3.csv" <<-EOF - .mode csv - SELECT idx, - CASE - WHEN mailbox = x'$after' OR hex(mailbox) LIKE '${after}00%' - THEN '$before' || SUBSTR(hex(mailbox), $((${#after}+1))) - WHEN hex(mailbox) LIKE '${after2}00%' - THEN '$before2' || SUBSTR(hex(mailbox), $((${#after2}+1))) - ELSE hex(mailbox) - END - FROM mailboxes - ORDER BY idx -EOF -diff -u --label="a/mailboxes.csv" --label="b/mailboxes.csv" \ - "$TMPDIR/mailboxes2.csv" "$TMPDIR/mailboxes3.csv" - -# vim: set filetype=sh : 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/02-delete/run b/tests/02-delete/run deleted file mode 100644 index f63c52c..0000000 --- a/tests/02-delete/run +++ /dev/null @@ -1,67 +0,0 @@ -doveadm -u "local" mailbox create "foo.bar" "foo.bar.baz" - -for m in "foo.bar" "foo.bar.baz" "INBOX"; do - sample_message | deliver -u "local" -- -m "$m" -done - -interimap -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" - -check_mailbox_list -check_mailboxes_status "foo.bar" "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" - -# 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." -interimap --target="local" --delete "foo.bar" - -check_mailbox_list -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" - -! 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)' -EOF -diff -u --label="a/mailboxes.csv" --label="b/mailboxes.csv" \ - "$TMPDIR/mailboxes.csv" "$TMPDIR/mailboxes2.csv" - -check_mailbox_list -check_mailboxes_status "foo.bar.baz" "INBOX" - -# vim: set filetype=sh : 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/04-resume/run b/tests/04-resume/run deleted file mode 100644 index 22d66bc..0000000 --- a/tests/04-resume/run +++ /dev/null @@ -1,98 +0,0 @@ -# create and populate a bunch of mailboxes -doveadm -u "local" mailbox create "foo" "foo.bar" "baz" -for ((i = 0; i < 8; i++)); do - sample_message | deliver -u "local" -- -m "foo" - sample_message | deliver -u "local" -- -m "foo.bar" - sample_message | deliver -u "local" -- -m "INBOX" -done -interimap -check_mailbox_list -check_mailboxes_status "foo" "foo.bar" "baz" "INBOX" - -# spoof UIDNEXT in the database -set_uidnext() { - local imap="$1" mailbox="$2" uidnext="$3" - sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <<-EOF - UPDATE $imap - SET UIDNEXT = $uidnext - WHERE idx = ( - SELECT idx - FROM mailboxes - WHERE mailbox = x'$mailbox' - ); - EOF -} - -# spoof "foo"'s UIDVALIDITY and UIDNEXT values -uidvalidity="$(doveadm -u "local" -f flow mailbox status uidvalidity "foo" | sed 's/.*=//')" -[ $uidvalidity -eq 4294967295 ] && uidvalidity2=1 || uidvalidity2=$((uidvalidity+1)) -doveadm -u "local" mailbox update --uid-validity "$uidvalidity2" "foo" -set_uidnext "local" "$(printf "%s" "foo" | xxd -ps)" 1 - -# verify that interimap chokes on the UIDVALIDITY change without doing any changes -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump.sql" <<-EOF - .dump -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" - -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump2.sql" <<-EOF - .dump -EOF -doveadm -u "local" mailbox status "all" "foo" >"$TMPDIR/foo.local2" -doveadm -u "remote" mailbox status "all" "foo" >"$TMPDIR/foo.remote2" - -diff -u --label="a/dump.sql" --label="b/dump.sql" "$TMPDIR/dump2.sql" "$TMPDIR/dump.sql" -diff -u --label="a/foo.local" --label="b/foo.remote" "$TMPDIR/foo.local" "$TMPDIR/foo.local2" -diff -u --label="a/foo.local" --label="b/foo.remote" "$TMPDIR/foo.remote" "$TMPDIR/foo.remote2" - - -# spoof UIDNEXT values for INBOX (local+remote) and foo.bar (remote) -set_uidnext "local" "$(printf "%s" "INBOX" | xxd -ps)" 2 -set_uidnext "remote" "$(printf "%s" "INBOX" | xxd -ps)" 2 -set_uidnext "remote" "$(printf "%s\\0%s" "foo" "bar" | xxd -ps)" 0 - -# set some flags and remove some messages for UIDs >2 -doveadm -u "local" flags add "\\Seen" mailbox "INBOX" 6,7 -doveadm -u "remote" flags add "\\Deleted" mailbox "INBOX" 6,8 - -doveadm -u "local" expunge mailbox "INBOX" 4,5 -doveadm -u "remote" expunge mailbox "INBOX" 3,4 -doveadm -u "remote" expunge mailbox "foo~bar" 5 - -# add new messages -sample_message | deliver -u "local" -- -m "foo.bar" -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" -check_mailbox_list -check_mailboxes_status "foo.bar" "INBOX" "baz" # ignore "foo" - - -# count entries in the mapping table -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/count" <<-EOF - SELECT COUNT(*) - FROM mapping NATURAL JOIN mailboxes - WHERE mailbox != x'$(printf "%s" "foo" | xxd -ps)' - GROUP BY idx - ORDER BY mailbox; -EOF - -# count messages: -# INBOX: 8-2-1 = 5 -# baz: 1 -# foo.bar: 8-1+1+1 = 9 -diff -u --label="a/count" --label="b/count" "$TMPDIR/count" - <<-EOF - 5 - 1 - 9 -EOF - -# vim: set filetype=sh : 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/05-repair/run b/tests/05-repair/run deleted file mode 100644 index 66f9ce9..0000000 --- a/tests/05-repair/run +++ /dev/null @@ -1,107 +0,0 @@ -# create some mailboxes and populate them -doveadm -u "local" mailbox create "foo.bar" -doveadm -u "remote" mailbox create "foo~bar" "baz" -for ((i = 0; i < 8; i++)); do - sample_message | deliver -u "local" -- -m "foo.bar" - sample_message | deliver -u "remote" -- -m "foo~bar" -done -for ((i = 0; i < 64; i++)); do - sample_message | deliver -u "remote" -- -m "baz" -done - -interimap -check_mailbox_list -check_mailboxes_status "foo.bar" "baz" "INBOX" - -# make more changes (flag updates, new massages, deletions) -sample_message | deliver -u "remote" -- -m "INBOX" -doveadm -u "local" expunge mailbox "baz" 1:10 -doveadm -u "remote" expunge mailbox "baz" "$(seq -s"," 1 2 32),$(seq -s"," 40 2 64)" -doveadm -u "local" expunge mailbox "foo.bar" 2,3,5:7,10 -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() { - local k="$1" v m hex="$(printf "%s\\0%s" "foo" "bar" | xxd -ps)" - shift - while [ $# -gt 0 ]; do - [ "$1" = "local" ] && m="foo.bar" || m="$(printf "%s" "foo.bar" | tr "." "~")" - v="$(doveadm -u "$1" -f flow mailbox status "${k,,[A-Z]}" "$m" | sed 's/.*=//')" - sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <<-EOF - UPDATE \`$1\` SET $k = $v - WHERE idx = (SELECT idx FROM mailboxes WHERE mailbox = x'$hex'); - EOF - shift - done -} - -spoof HIGHESTMODSEQ "local" "remote" -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump.sql" <<-EOF - .dump -EOF -doveadm -u "local" mailbox status "all" "foo.bar" >"$TMPDIR/foo-bar.status.local" -doveadm -u "remote" mailbox status "all" "foo~bar" >"$TMPDIR/foo-bar.status.remote" - - -# verify that without --repair interimap does nothing due to the spoofed HIGHESTMODSEQ values -interimap "foo.bar" - -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump2.sql" <<-EOF - .dump -EOF -doveadm -u "local" mailbox status all "foo.bar" >"$TMPDIR/foo-bar.status2.local" -doveadm -u "remote" mailbox status all "foo~bar" >"$TMPDIR/foo-bar.status2.remote" -diff -u --label="a/dump.sql" --label="b/dump.sql" "$TMPDIR/dump.sql" "$TMPDIR/dump2.sql" -diff -u --label="a/foo_bar.local" --label="a/foo_bar.local" "$TMPDIR/foo-bar.status.local" "$TMPDIR/foo-bar.status2.local" -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 -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" - -# 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 -# luid 16 <-> ruid 8 has both \Answered and \Seen -xcgrep 5 '^WARNING: Missed flag update in foo\.bar for ' <"$STDERR" -xcgrep 5 '^WARNING: Conflicting flag update in foo\.bar ' <"$STDERR" - -# luid 2 <-> ruid 10 -xcgrep 1 -E '^WARNING: Pair \(lUID,rUID\) = \([0-9]+,[0-9]+\) vanished from foo\.bar\. Repairing\.$' <"$STDERR" - -# 6-1 (luid 2 <-> ruid 10 is gone from both) -xcgrep 5 -E '^local\(foo\.bar\): WARNING: UID [0-9]+ disappeared. Redownloading remote UID [0-9]+\.$' <"$STDERR" - -# 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" - -# 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" - -# 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 - -check_mailbox_list -check_mailboxes_status "baz" "foo.bar" - -interimap -check_mailboxes_status "baz" "foo.bar" "INBOX" - -# vim: set filetype=sh : 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/06-largeint/run b/tests/06-largeint/run deleted file mode 100644 index b08bcfa..0000000 --- a/tests/06-largeint/run +++ /dev/null @@ -1,38 +0,0 @@ -doveadm -u "local" mailbox create "foo" "bar" "baz" -doveadm -u "remote" mailbox create "foo" "bar" "baz" - -doveadm -u "local" mailbox update --uid-validity 1 "INBOX" -doveadm -u "local" mailbox update --uid-validity 2147483647 "foo" # 2^31-1 -doveadm -u "local" mailbox update --uid-validity 2147483648 "bar" # 2^31 -doveadm -u "local" mailbox update --uid-validity 4294967295 "baz" # 2^32-1 - -doveadm -u "remote" mailbox update --uid-validity 4294967295 "INBOX" # 2^32-1 -doveadm -u "remote" mailbox update --uid-validity 2147483648 "foo" # 2^31 -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 - done - interimap - check_mailbox_status "INBOX" "foo" "bar" "baz" -} -run - -# raise UIDNEXT AND HIGHESTMODSEQ close to the max values (resp. 2^32-1 och 2^63-1) -doveadm -u "local" mailbox update --min-next-uid 2147483647 --min-highest-modseq 9223372036854775807 "INBOX" # 2^31-1, 2^63-1 -doveadm -u "local" mailbox update --min-next-uid 2147483647 --min-highest-modseq 9223372036854775807 "foo" # 2^31-1, 2^63-1 -doveadm -u "local" mailbox update --min-next-uid 2147483648 --min-highest-modseq 9223372036854775808 "bar" # 2^31, 2^63 -doveadm -u "local" mailbox update --min-next-uid 2147483648 --min-highest-modseq 9223372036854775808 "baz" # 2^31, 2^63 - -doveadm -u "remote" mailbox update --min-next-uid 4294967168 --min-highest-modseq 18446744073709551488 "INBOX" # 2^32-128, 2^64-128 -doveadm -u "remote" mailbox update --min-next-uid 2147483776 --min-highest-modseq 9223372036854775936 "foo" # 2^31+128, 2^63+128 -doveadm -u "remote" mailbox update --min-next-uid 2147483648 --min-highest-modseq 9223372036854775808 "bar" # 2^31, 2^63 - -run - -# vim: set filetype=sh : diff --git a/tests/07-sync-live-multi/local.conf b/tests/07-sync-live-multi/local.conf deleted file mode 100644 index baae39d..0000000 --- a/tests/07-sync-live-multi/local.conf +++ /dev/null @@ -1,30 +0,0 @@ -namespace inbox { - separator = / - location = dbox:~/inbox:LAYOUT=index - inbox = yes - list = yes -} - -namespace foo { - separator = / - prefix = foo/ - location = dbox:~/foo:LAYOUT=index - inbox = no - list = yes -} - -namespace bar { - separator = / - prefix = bar/ - location = dbox:~/bar:LAYOUT=index - inbox = no - list = yes -} - -namespace baz { - separator = / - prefix = baz/ - location = dbox:~/baz:LAYOUT=index - inbox = no - 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-multi/run b/tests/07-sync-live-multi/run deleted file mode 100644 index 15a27fd..0000000 --- a/tests/07-sync-live-multi/run +++ /dev/null @@ -1,138 +0,0 @@ -# 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 - - -# mailbox list (as seen on local) and alphabet -declare -a mailboxes=( "INBOX" ) alphabet=() -str="#+-0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" -for ((i=0; i < ${#str}; i++)); do - alphabet[i]="${str:i:1}" -done - -declare -a targets=( "local" "remote" "remote2" "remote3" ) - -timer=$(( $(date +%s) + 30 )) -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 - case "$u" in - local) ns="$(shuf -n1 -e "foo/" "bar/" "baz/")";; - remote) ns="foo/";; - remote2) ns="bar/";; - remote3) ns="baz/";; - *) echo "Uh?" >&2; exit 1;; - 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')" - done - mailboxes+=( "$ns$m" ) - case "$u" in - local) m="$ns$m";; - remote) m="${m//\//^}";; - remote2) m="${m//\//\\}";; - remote3) m="${m//\//\?}";; - *) echo "Uh?" >&2; exit 1;; - esac - doveadm -u "$u" mailbox create -- "$m" - fi - - # EXPUNGE some messages - 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" - done < <(doveadm -u "$u" search all | shuf -n "$n") - - # 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 - n="$(shuf -n1 -i0-9)" - while read guid uid; do - a="$(shuf -n1 -e add remove replace)" - doveadm -u "$u" flags "$a" "\\Seen" mailbox-guid "$guid" uid "$uid" - done < <(doveadm -u "$u" search all | shuf -n "$n") - - # 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[@]}")" - if [ "$u" = "remote" ]; then - case "$m" in - foo/*) u="remote"; 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;; - esac - fi - - # deliver between 1 and 5 messages to the chosen mailbox - n="$(shuf -n1 -i1-5)" - for (( i=0; i < n; i++)); do - sample_message | deliver -u "$u" -- -m "$m" - done - - # sleep a little bit - sleep "$(printf "0.%03d" "$(shuf -n1 -i1-999)")" -done - -# wait a little longer so interimap has time to run loop() again and -# synchronize outstanding changes, then terminate the processes we -# started above -sleep 2 - -abort -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="remote2/mailboxes" \ - <( doveadm -u "local" mailbox list | sed -n "s,^bar/,,p" | sort ) \ - <( doveadm -u "remote2" mailbox list | tr '\\' '/' | sort ) -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 - case "$m" in - foo/*) u="remote"; 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;; - esac - blob="x'$(printf "%s" "$mb" | tr "/" "\\0" | xxd -c256 -ps)'" - check_mailbox_status2 "$blob" "$m" "$u" "$mr" -done - -# vim: set filetype=sh : 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/07-sync-live/run b/tests/07-sync-live/run deleted file mode 100644 index 04d8247..0000000 --- a/tests/07-sync-live/run +++ /dev/null @@ -1,80 +0,0 @@ -# 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 - -# mailbox list and alphabet (exclude &, / and ~, which dovecot treats specially) -declare -a mailboxes=( "INBOX" ) alphabet=() -str="!\"#\$'()+,-0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\[\\\]_\`abcdefghijklmnopqrstuvwxyz{|}" -for ((i=0; i < ${#str}; i++)); do - alphabet[i]="${str:i:1}" -done - -timer=$(( $(date +%s) + 30 )) -while [ $(date +%s) -le $timer ]; do - # create new mailbox with 10% probability - if [ $(shuf -n1 -i0-9) -eq 0 ]; then - 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')" - done - mailboxes+=( "$m" ) - u="$(shuf -n1 -e "local" "remote")" # choose target at random - [ "$u" = "local" ] || m="${m//./^}" - doveadm -u "$u" mailbox create -- "$m" - fi - - # EXPUNGE some messages - u="$(shuf -n1 -e "local" "remote")" # choose target at random - n="$(shuf -n1 -i0-3)" - while read guid uid; do - doveadm -u "$u" expunge mailbox-guid "$guid" uid "$uid" - done < <(doveadm -u "$u" search all | shuf -n "$n") - - # 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 "local" "remote")" # choose target at random - n="$(shuf -n1 -i0-9)" - while read guid uid; do - a="$(shuf -n1 -e add remove replace)" - doveadm -u "$u" flags "$a" "\\Seen" mailbox-guid "$guid" uid "$uid" - done < <(doveadm -u "$u" search all | shuf -n "$n") - - # 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[@]}")" - [ "$u" = "local" ] || m="${m//./^}" - - # deliver between 1 and 5 messages to the chosen mailbox - n="$(shuf -n1 -i1-5)" - for (( i=0; i < n; i++)); do - sample_message | deliver -u "$u" -- -m "$m" - done - - # sleep a little bit - sleep "$(printf "0.%03d" "$(shuf -n1 -i1-999)")" -done - -# wait a little longer so interimap has time to run loop() again and -# synchronize outstanding changes, then terminate the process we started -# above -sleep 2 - -abort -trap - EXIT INT TERM - -check_mailbox_list -check_mailboxes_status "${mailboxes[@]}" - -# 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/db-upgrade-0-1/after.sql b/tests/db-upgrade-0-1/after.sql new file mode 100644 index 0000000..18b0ad7 --- /dev/null +++ b/tests/db-upgrade-0-1/after.sql @@ -0,0 +1,14 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE local (idx INTEGER NOT NULL PRIMARY KEY REFERENCES mailboxes(idx), UIDVALIDITY UNSIGNED INT NOT NULL CHECK (UIDVALIDITY > 0), UIDNEXT UNSIGNED INT NOT NULL, HIGHESTMODSEQ UNSIGNED BIGINT NOT NULL); +CREATE TABLE remote (idx INTEGER NOT NULL PRIMARY KEY REFERENCES mailboxes(idx), UIDVALIDITY UNSIGNED INT NOT NULL CHECK (UIDVALIDITY > 0), UIDNEXT UNSIGNED INT NOT NULL, HIGHESTMODSEQ UNSIGNED BIGINT NOT NULL); +CREATE TABLE mapping (idx INTEGER NOT NULL REFERENCES mailboxes(idx), lUID UNSIGNED INT NOT NULL CHECK (lUID > 0), rUID UNSIGNED INT NOT NULL CHECK (rUID > 0), PRIMARY KEY (idx,lUID), UNIQUE (idx,rUID)); +CREATE TABLE IF NOT EXISTS "mailboxes" (idx INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, mailbox BLOB COLLATE BINARY NOT NULL CHECK (mailbox != '') UNIQUE, subscribed BOOLEAN NOT NULL); +INSERT INTO mailboxes VALUES(1,X'61006231006332',0); +INSERT INTO mailboxes VALUES(2,X'61006231006331',0); +INSERT INTO mailboxes VALUES(3,X'494e424f58',0); +INSERT INTO mailboxes VALUES(4,X'6132',0); +INSERT INTO mailboxes VALUES(5,X'610062320063',0); +DELETE FROM sqlite_sequence; +INSERT INTO sqlite_sequence VALUES('mailboxes',5); +COMMIT; diff --git a/tests/db-upgrade-0-1/before.sql b/tests/db-upgrade-0-1/before.sql new file mode 100644 index 0000000..333a1dc --- /dev/null +++ b/tests/db-upgrade-0-1/before.sql @@ -0,0 +1,14 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE mailboxes (idx INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, mailbox TEXT NOT NULL CHECK (mailbox != '') UNIQUE, subscribed BOOLEAN NOT NULL); +INSERT INTO mailboxes VALUES(1,'a.b1.c2',0); +INSERT INTO mailboxes VALUES(2,'a.b1.c1',0); +INSERT INTO mailboxes VALUES(3,'INBOX',0); +INSERT INTO mailboxes VALUES(4,'a2',0); +INSERT INTO mailboxes VALUES(5,'a.b2.c',0); +CREATE TABLE local (idx INTEGER NOT NULL PRIMARY KEY REFERENCES mailboxes(idx), UIDVALIDITY UNSIGNED INT NOT NULL CHECK (UIDVALIDITY > 0), UIDNEXT UNSIGNED INT NOT NULL, HIGHESTMODSEQ UNSIGNED BIGINT NOT NULL); +CREATE TABLE remote (idx INTEGER NOT NULL PRIMARY KEY REFERENCES mailboxes(idx), UIDVALIDITY UNSIGNED INT NOT NULL CHECK (UIDVALIDITY > 0), UIDNEXT UNSIGNED INT NOT NULL, HIGHESTMODSEQ UNSIGNED BIGINT NOT NULL); +CREATE TABLE mapping (idx INTEGER NOT NULL REFERENCES mailboxes(idx), lUID UNSIGNED INT NOT NULL CHECK (lUID > 0), rUID UNSIGNED INT NOT NULL CHECK (rUID > 0), PRIMARY KEY (idx,lUID), UNIQUE (idx,rUID)); +DELETE FROM sqlite_sequence; +INSERT INTO sqlite_sequence VALUES('mailboxes',5); +COMMIT; 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/db-upgrade-0-1/t b/tests/db-upgrade-0-1/t new file mode 100644 index 0000000..088008e --- /dev/null +++ b/tests/db-upgrade-0-1/t @@ -0,0 +1,34 @@ +# 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" || error "Couldn't import DB" + +# migrate +interimap || error "Couldn't upgrade DB" + +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 +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump.sql" <<-EOF + DELETE FROM local; + DELETE FROM remote; + .dump +EOF + +# re-import and dump the expected dump to work around SQLite format +# differences across versions +sqlite3 "$XDG_DATA_HOME/interimap/remote2.db" <"$TESTDIR/after.sql" +sqlite3 "$XDG_DATA_HOME/interimap/remote2.db" >"$TMPDIR/dump-expected.sql" <<-EOF + .dump +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" \ + || 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/delete/t b/tests/delete/t new file mode 100644 index 0000000..c38d4d3 --- /dev/null +++ b/tests/delete/t @@ -0,0 +1,95 @@ +doveadm -u "local" mailbox create "foo.bar" "foo.bar.baz" + +for m in "foo.bar" "foo.bar.baz" "INBOX"; do + sample_message | deliver -u "local" -- -m "$m" +done + +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 + + +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" +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" || 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 +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" || error "SQL dumps differ" + +! doveadm -u "local" mailbox status uidvalidity "foo.bar" # gone + doveadm -u "remote" mailbox status uidvalidity "foo^bar" + +# 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.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_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/largeint/t b/tests/largeint/t new file mode 100644 index 0000000..b0877d5 --- /dev/null +++ b/tests/largeint/t @@ -0,0 +1,39 @@ +doveadm -u "local" mailbox create "foo" "bar" "baz" +doveadm -u "remote" mailbox create "foo" "bar" "baz" + +doveadm -u "local" mailbox update --uid-validity 1 "INBOX" +doveadm -u "local" mailbox update --uid-validity 2147483647 "foo" # 2^31-1 +doveadm -u "local" mailbox update --uid-validity 2147483648 "bar" # 2^31 +doveadm -u "local" mailbox update --uid-validity 4294967295 "baz" # 2^32-1 + +doveadm -u "remote" mailbox update --uid-validity 4294967295 "INBOX" # 2^32-1 +doveadm -u "remote" mailbox update --uid-validity 2147483648 "foo" # 2^31 +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 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 || error + check_mailbox_list + check_mailbox_status "INBOX" "foo" "bar" "baz" +} +run + +# raise UIDNEXT AND HIGHESTMODSEQ close to the max values (resp. 2^32-1 och 2^63-1) +doveadm -u "local" mailbox update --min-next-uid 2147483647 --min-highest-modseq 9223372036854775807 "INBOX" # 2^31-1, 2^63-1 +doveadm -u "local" mailbox update --min-next-uid 2147483647 --min-highest-modseq 9223372036854775807 "foo" # 2^31-1, 2^63-1 +doveadm -u "local" mailbox update --min-next-uid 2147483648 --min-highest-modseq 9223372036854775808 "bar" # 2^31, 2^63 +doveadm -u "local" mailbox update --min-next-uid 2147483648 --min-highest-modseq 9223372036854775808 "baz" # 2^31, 2^63 + +doveadm -u "remote" mailbox update --min-next-uid 4294967168 --min-highest-modseq 18446744073709551488 "INBOX" # 2^32-128, 2^64-128 +doveadm -u "remote" mailbox update --min-next-uid 2147483776 --min-highest-modseq 9223372036854775936 "foo" # 2^31+128, 2^63+128 +doveadm -u "remote" mailbox update --min-next-uid 2147483648 --min-highest-modseq 9223372036854775808 "bar" # 2^31, 2^63 + +run + +# vim: set filetype=sh : diff --git a/tests/list b/tests/list new file mode 100644 index 0000000..21aa3f4 --- /dev/null +++ b/tests/list @@ -0,0 +1,37 @@ +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 + +. Live synchronization (60s) + sync-live local/remote simulation + sync-live-crippled local/remote simulation (crippled remote) + sync-live-multi local/remote1+remote2+remote3 simulation (3 local namespaces) 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/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/rename-exists-db/t b/tests/rename-exists-db/t new file mode 100644 index 0000000..cb6cfcd --- /dev/null +++ b/tests/rename-exists-db/t @@ -0,0 +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_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" || 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/rename-exists-local/t b/tests/rename-exists-local/t new file mode 100644 index 0000000..190f49a --- /dev/null +++ b/tests/rename-exists-local/t @@ -0,0 +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_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" || 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/rename-exists-remote/t b/tests/rename-exists-remote/t new file mode 100644 index 0000000..be16a12 --- /dev/null +++ b/tests/rename-exists-remote/t @@ -0,0 +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_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" || 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/rename-inferiors/t b/tests/rename-inferiors/t new file mode 100644 index 0000000..9267e6f --- /dev/null +++ b/tests/rename-inferiors/t @@ -0,0 +1,100 @@ +doveadm -u "local" mailbox create "root.from" "root.from.child" "root.from.child2" "root.from.child.grandchild" +doveadm -u "remote" mailbox create "root^sibbling" "root^sibbling^grandchild" "root2" + +for m in "root.from" "root.from.child" "root.from.child2" "root.from.child.grandchild" "INBOX"; do + sample_message | deliver -u "local" -- -m "$m" +done +for m in "root^sibbling" "root^sibbling^grandchild" "root2" "INBOX"; do + sample_message | deliver -u "remote" -- -m "$m" +done + +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 + .mode csv + SELECT idx, hex(mailbox) + FROM mailboxes + ORDER BY idx +EOF + +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 + + +# rename 'root.from' to 'from.root', including inferiors +step_start "existing source with inferiors" +interimap --rename "root.from" "from.root" +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 -u -ps)" +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes2.csv" <<-EOF + .mode csv + SELECT idx, + CASE + WHEN mailbox = x'$after' OR hex(mailbox) LIKE '${after}00%' + THEN '$before' || SUBSTR(hex(mailbox), $((${#after}+1))) + 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 + + +# rename \NonExistent root and check that its children move +step_start "\\NonExistent source with inferiors" +interimap --rename "root" "newroot" +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 -u -ps)" +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes3.csv" <<-EOF + .mode csv + SELECT idx, + CASE + WHEN mailbox = x'$after' OR hex(mailbox) LIKE '${after}00%' + THEN '$before' || SUBSTR(hex(mailbox), $((${#after}+1))) + WHEN hex(mailbox) LIKE '${after2}00%' + THEN '$before2' || SUBSTR(hex(mailbox), $((${#after2}+1))) + ELSE hex(mailbox) + END + FROM mailboxes + ORDER BY idx +EOF +diff -u --label="a/mailboxes.csv" --label="b/mailboxes.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/repair/t b/tests/repair/t new file mode 100644 index 0000000..6b205ea --- /dev/null +++ b/tests/repair/t @@ -0,0 +1,107 @@ +# create some mailboxes and populate them +doveadm -u "local" mailbox create "foo.bar" +doveadm -u "remote" mailbox create "foo~bar" "baz" +for ((i = 0; i < 8; i++)); do + sample_message | deliver -u "local" -- -m "foo.bar" + sample_message | deliver -u "remote" -- -m "foo~bar" +done +for ((i = 0; i < 64; i++)); do + sample_message | deliver -u "remote" -- -m "baz" +done + +interimap_init +check_mailbox_list +check_mailboxes_status "foo.bar" "baz" "INBOX" + +# make more changes (flag updates, new massages, deletions) +sample_message | deliver -u "remote" -- -m "INBOX" +doveadm -u "local" expunge mailbox "baz" 1:10 +doveadm -u "remote" expunge mailbox "baz" "$(seq -s"," 1 2 32),$(seq -s"," 40 2 64)" +doveadm -u "local" expunge mailbox "foo.bar" 2,3,5:7,10 +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() { + local k="$1" v m hex="$(printf "%s\\0%s" "foo" "bar" | xxd -ps)" + shift + while [ $# -gt 0 ]; do + [ "$1" = "local" ] && m="foo.bar" || m="$(printf "%s" "foo.bar" | tr "." "~")" + v="$(doveadm -u "$1" -f flow mailbox status "${k,,[A-Z]}" "$m" | sed 's/.*=//')" + sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <<-EOF + UPDATE \`$1\` SET $k = $v + WHERE idx = (SELECT idx FROM mailboxes WHERE mailbox = x'$hex'); + EOF + shift + done +} + +spoof HIGHESTMODSEQ "local" "remote" +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump.sql" <<-EOF + .dump +EOF +doveadm -u "local" mailbox status "all" "foo.bar" >"$TMPDIR/foo-bar.status.local" +doveadm -u "remote" mailbox status "all" "foo~bar" >"$TMPDIR/foo-bar.status.remote" + + +# verify that without --repair interimap does nothing due to the spoofed HIGHESTMODSEQ values +interimap "foo.bar" || error + +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump2.sql" <<-EOF + .dump +EOF +doveadm -u "local" mailbox status all "foo.bar" >"$TMPDIR/foo-bar.status2.local" +doveadm -u "remote" mailbox status all "foo~bar" >"$TMPDIR/foo-bar.status2.remote" +diff -u --label="a/dump.sql" --label="b/dump.sql" "$TMPDIR/dump.sql" "$TMPDIR/dump2.sql" +diff -u --label="a/foo_bar.local" --label="a/foo_bar.local" "$TMPDIR/foo-bar.status.local" "$TMPDIR/foo-bar.status2.local" +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* +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" || 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 +# luid 16 <-> ruid 8 has both \Answered and \Seen +xcgrep 5 '^WARNING: Missed flag update in foo\.bar for ' <"$STDERR" +xcgrep 5 '^WARNING: Conflicting flag update in foo\.bar ' <"$STDERR" + +# luid 2 <-> ruid 10 +xcgrep 1 -E '^WARNING: Pair \(lUID,rUID\) = \([0-9]+,[0-9]+\) vanished from foo\.bar\. Repairing\.$' <"$STDERR" + +# 6-1 (luid 2 <-> ruid 10 is gone from both) +xcgrep 5 -E '^local\(foo\.bar\): WARNING: UID [0-9]+ disappeared. Redownloading remote UID [0-9]+\.$' <"$STDERR" + +# 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" + +grep -E '^local\(baz\): Removed 24 UID\(s\) ' <"$STDERR" || error +grep -E '^remote\(baz\): Removed 5 UID\(s\) ' <"$STDERR" || error + +# 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" + +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 || 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/resume/t b/tests/resume/t new file mode 100644 index 0000000..cb0208c --- /dev/null +++ b/tests/resume/t @@ -0,0 +1,98 @@ +# create and populate a bunch of mailboxes +doveadm -u "local" mailbox create "foo" "foo.bar" "baz" +for ((i = 0; i < 8; i++)); do + sample_message | deliver -u "local" -- -m "foo" + sample_message | deliver -u "local" -- -m "foo.bar" + sample_message | deliver -u "local" -- -m "INBOX" +done +interimap_init +check_mailbox_list +check_mailboxes_status "foo" "foo.bar" "baz" "INBOX" + +# spoof UIDNEXT in the database +set_uidnext() { + local imap="$1" mailbox="$2" uidnext="$3" + sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <<-EOF + UPDATE $imap + SET UIDNEXT = $uidnext + WHERE idx = ( + SELECT idx + FROM mailboxes + WHERE mailbox = x'$mailbox' + ); + EOF +} + +# spoof "foo"'s UIDVALIDITY and UIDNEXT values +uidvalidity="$(doveadm -u "local" -f flow mailbox status uidvalidity "foo" | sed 's/.*=//')" +[ $uidvalidity -eq 4294967295 ] && uidvalidity2=1 || uidvalidity2=$((uidvalidity+1)) +doveadm -u "local" mailbox update --uid-validity "$uidvalidity2" "foo" +set_uidnext "local" "$(printf "%s" "foo" | xxd -ps)" 1 + +# verify that interimap chokes on the UIDVALIDITY change without doing any changes +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump.sql" <<-EOF + .dump +EOF +doveadm -u "local" mailbox status "all" "foo" >"$TMPDIR/foo.local" +doveadm -u "remote" mailbox status "all" "foo" >"$TMPDIR/foo.remote" + +! 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 +EOF +doveadm -u "local" mailbox status "all" "foo" >"$TMPDIR/foo.local2" +doveadm -u "remote" mailbox status "all" "foo" >"$TMPDIR/foo.remote2" + +diff -u --label="a/dump.sql" --label="b/dump.sql" "$TMPDIR/dump2.sql" "$TMPDIR/dump.sql" +diff -u --label="a/foo.local" --label="b/foo.remote" "$TMPDIR/foo.local" "$TMPDIR/foo.local2" +diff -u --label="a/foo.local" --label="b/foo.remote" "$TMPDIR/foo.remote" "$TMPDIR/foo.remote2" + + +# spoof UIDNEXT values for INBOX (local+remote) and foo.bar (remote) +set_uidnext "local" "$(printf "%s" "INBOX" | xxd -ps)" 2 +set_uidnext "remote" "$(printf "%s" "INBOX" | xxd -ps)" 2 +set_uidnext "remote" "$(printf "%s\\0%s" "foo" "bar" | xxd -ps)" 0 + +# set some flags and remove some messages for UIDs >2 +doveadm -u "local" flags add "\\Seen" mailbox "INBOX" 6,7 +doveadm -u "remote" flags add "\\Deleted" mailbox "INBOX" 6,8 + +doveadm -u "local" expunge mailbox "INBOX" 4,5 +doveadm -u "remote" expunge mailbox "INBOX" 3,4 +doveadm -u "remote" expunge mailbox "foo~bar" 5 + +# add new messages +sample_message | deliver -u "local" -- -m "foo.bar" +sample_message | deliver -u "remote" -- -m "foo~bar" +sample_message | deliver -u "local" -- -m "baz" + +interimap "foo.bar" "InBoX" "baz" # ignore "foo" +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" + + +# count entries in the mapping table +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/count" <<-EOF + SELECT COUNT(*) + FROM mapping NATURAL JOIN mailboxes + WHERE mailbox != x'$(printf "%s" "foo" | xxd -ps)' + GROUP BY idx + ORDER BY mailbox; +EOF + +# count messages: +# INBOX: 8-2-1 = 5 +# baz: 1 +# foo.bar: 8-1+1+1 = 9 +diff -u --label="a/count" --label="b/count" "$TMPDIR/count" - <<-EOF + 5 + 1 + 9 +EOF + +# vim: set filetype=sh : diff --git a/tests/run b/tests/run index ee11757..cb52518 100755 --- a/tests/run +++ b/tests/run @@ -22,27 +22,27 @@ 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" +TESTDIR="$(dirname -- "$0")/$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")" +ROOTDIR="$(mktemp --tmpdir="${TMPDIR:-/dev/shm}" --directory "$1.XXXXXXXXXX")" trap 'rm -rf -- "$ROOTDIR"' EXIT INT TERM -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,24 +60,35 @@ environ_set() { # Prepare the test harness prepare() { declare -a ENVIRON=() - local src cfg target u home + local src cfg target u home n capability + if [ -f "$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 + log_path = $HOME_local/mail.log + mail_home = $home + mail_location = dbox:~/inbox:LAYOUT=index mailbox_list_index = yes ssl = no + namespace inbox { + inbox = yes + } EOF - cat >>"$home/.config/dovecot/config" <"$src" + if [ -f "$TESTDIR/$u.conf" ]; then + cat >>"$home/.config/dovecot/config" <"$TESTDIR/$u.conf" + fi + environ_set "$u" + mkdir -pm0755 -- "$home/.local/bin" cat >"$home/.local/bin/doveadm" <<-EOF #!/bin/sh exec env -i ${ENVIRON[@]@Q} \\ @@ -89,36 +100,62 @@ prepare() { # 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" + 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" ]; then + cat <"$TESTDIR/interimap$n.conf" >>"$HOME_local/.config/interimap/config$n" + 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 + EOF + if [ -f "$TESTDIR/interimap$n.local" ]; then + cat <"$TESTDIR/interimap$n.local" >>"$HOME_local/.config/interimap/config$n" + fi + + # `doveadm exec imap` ignores 'imap_capability' from doveconf/config + capability="$(doveconf -c "$home/.config/dovecot/config" -h imap_capability)" + cat >>"$HOME_local/.config/interimap/config$n" <<-EOF [remote] type = tunnel - command = exec ${home@Q}/.local/bin/doveadm exec imap + command = exec ${home@Q}/.local/bin/doveadm exec imap ${capability:+-oimap_capability=${capability@Q}} null-stderr = NO EOF + if [ -f "$TESTDIR/interimap$n.remote" ]; then + cat <"$TESTDIR/interimap$n.remote" >>"$HOME_local/.config/interimap/config$n" + fi done } prepare # Wrappers for interimap(1) and doveadm(1) interimap() { - declare -a ENVIRON=() + declare -a ENVIRON=() r=0 environ_set "local" - env -i "${ENVIRON[@]}" perl -I./lib -T ./interimap "$@" + env -i "${ENVIRON[@]}" perl -I./lib -T ./interimap "$@" 2>"$STDERR" || r=$? + cat "$STDERR" >&2 + return $r +} +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 @@ -167,9 +204,7 @@ 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" @@ -177,16 +212,18 @@ dump_test_result() { printf "%s\\n\\n" "$above" done - printf "(local) interimap configuration:\\n%s\\n" "$below" - cat <"$HOME_local/.config/interimap/config" - printf "%s\\n\\n" "$above" + 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 "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" } @@ -225,7 +262,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 @@ -304,38 +341,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 TMPDIR TESTDIR STDERR "${ENVIRON[@]}" export -f environ_set doveadm interimap sqlite3 sample_message deliver +export -f interimap_init 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 +# +# 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 . +#---------------------------------------------------------------------- + +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/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..76c08e0 --- /dev/null +++ b/tests/sync-live-crippled/remote.conf @@ -0,0 +1,6 @@ +namespace inbox { + separator = ^ +} + +# strict minimum of IMAP capabilities required for interimap to work +imap_capability = IMAP4rev1 ENABLE UIDPLUS LIST-EXTENDED QRESYNC LIST-STATUS 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/sync-live-multi/local.conf b/tests/sync-live-multi/local.conf new file mode 100644 index 0000000..baae39d --- /dev/null +++ b/tests/sync-live-multi/local.conf @@ -0,0 +1,30 @@ +namespace inbox { + separator = / + location = dbox:~/inbox:LAYOUT=index + inbox = yes + list = yes +} + +namespace foo { + separator = / + prefix = foo/ + location = dbox:~/foo:LAYOUT=index + inbox = no + list = yes +} + +namespace bar { + separator = / + prefix = bar/ + location = dbox:~/bar:LAYOUT=index + inbox = no + list = yes +} + +namespace baz { + separator = / + prefix = baz/ + location = dbox:~/baz:LAYOUT=index + inbox = no + list = yes +} 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/sync-live-multi/t b/tests/sync-live-multi/t new file mode 100644 index 0000000..9b129ec --- /dev/null +++ b/tests/sync-live-multi/t @@ -0,0 +1,127 @@ +TIMEOUT=60 + +# mailbox list (as seen on local) and alphabet +declare -a MAILBOXES=( "INBOX" ) ALPHABET=() +str="#+-0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" +for ((i=0; i < ${#str}; i++)); do + ALPHABET[i]="${str:i:1}" +done + +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) + 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 + case "$u" in + local) ns="$(shuf -n1 -e "foo/" "bar/" "baz/")";; + remote1) ns="foo/";; + remote2) ns="bar/";; + remote3) ns="baz/";; + *) 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')" + done + MAILBOXES+=( "$ns$m" ) + case "$u" in + local) m="$ns$m";; + remote1) m="${m//\//^}";; + remote2) m="${m//\//\\}";; + remote3) m="${m//\//\?}";; + *) error "Uh?";; + esac + doveadm -u "$u" mailbox create -- "$m" + fi + + # EXPUNGE some messages + 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" + done < <(doveadm -u "$u" search all | shuf -n "$n") + + # 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 + n="$(shuf -n1 -i0-9)" + while read guid uid; do + a="$(shuf -n1 -e add remove replace)" + doveadm -u "$u" flags "$a" "\\Seen" mailbox-guid "$guid" uid "$uid" + done < <(doveadm -u "$u" search all | shuf -n "$n") + + # 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[@]}")" + if [ "$u" = "remote" ]; then + case "$m" in + 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 "remote1" "remote2" "remote3")";; + *) error "Uh? $m";; + esac + fi + + # deliver between 1 and 5 messages to the chosen mailbox + n="$(shuf -n1 -i1-5)" + for (( i=0; i < n; i++)); do + sample_message | deliver -u "$u" -- -m "$m" + done + + # 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 +# synchronize outstanding changes, then terminate the processes we +# started above +sleep 2 + +ptree_abort ${PID[@]} +trap - EXIT INT TERM + +# check that the mailbox lists match +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 ) +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 + case "$m" in + 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;; + *) error "Uh? $m";; + esac + blob="x'$(printf "%s" "$mb" | tr "/" "\\0" | xxd -c256 -ps)'" + check_mailbox_status2 "$blob" "$m" "$u" "$mr" +done + +# vim: set filetype=sh : 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/sync-live/t b/tests/sync-live/t new file mode 100644 index 0000000..19d1e08 --- /dev/null +++ b/tests/sync-live/t @@ -0,0 +1,76 @@ +TIMEOUT=60 + +# mailbox list and alphabet (exclude &, / and ~, which dovecot treats specially) +declare -a MAILBOXES=( "INBOX" ) ALPHABET=() +str="!\"#\$'()+,-0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\[\\\]_\`abcdefghijklmnopqrstuvwxyz{|}" +for ((i=0; i < ${#str}; i++)); do + ALPHABET[i]="${str:i:1}" +done + +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 + 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')" + done + MAILBOXES+=( "$m" ) + u="$(shuf -n1 -e "local" "remote")" # choose target at random + [ "$u" = "local" ] || m="${m//./^}" + doveadm -u "$u" mailbox create -- "$m" + fi + + # EXPUNGE some messages + u="$(shuf -n1 -e "local" "remote")" # choose target at random + n="$(shuf -n1 -i0-3)" + while read guid uid; do + doveadm -u "$u" expunge mailbox-guid "$guid" uid "$uid" + done < <(doveadm -u "$u" search all | shuf -n "$n") + + # 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 "local" "remote")" # choose target at random + n="$(shuf -n1 -i0-9)" + while read guid uid; do + a="$(shuf -n1 -e add remove replace)" + doveadm -u "$u" flags "$a" "\\Seen" mailbox-guid "$guid" uid "$uid" + done < <(doveadm -u "$u" search all | shuf -n "$n") + + # 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[@]}")" + [ "$u" = "local" ] || m="${m//./^}" + + # deliver between 1 and 5 messages to the chosen mailbox + n="$(shuf -n1 -i1-5)" + for (( i=0; i < n; i++)); do + sample_message | deliver -u "$u" -- -m "$m" + done + + # 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 +# synchronize outstanding changes, then terminate the process we started +# above +sleep 2 + +ptree_abort $PID +trap - EXIT INT TERM + +check_mailbox_list +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 : -- cgit v1.2.3