diff options
author | Guilhem Moulin <guilhem@fripost.org> | 2019-11-09 03:13:45 +0100 |
---|---|---|
committer | Guilhem Moulin <guilhem@fripost.org> | 2019-11-13 06:23:56 +0100 |
commit | 67440844c422ee30b31df9a46a7f99ac0e833add (patch) | |
tree | 989381e5b94d5939dafdd1e99c7db2ada95355ec | |
parent | b9da6cc7ecf71026d1023dc3354b820c7518426e (diff) |
Refactor and improve test suite.
118 files changed, 944 insertions, 638 deletions
@@ -33,7 +33,7 @@ $(MANUALS): %: %.md pandoc -s -f json -t man+smart -o "$@" test: - @for t in tests/*; do if [ -f "$$t/run" ]; then ./tests/run "$$t" || exit 1; fi; done + @./tests/run-all HTML_ROOTDIR ?= ./doc CSS ?= /usr/share/javascript/bootstrap/css/bootstrap.min.css @@ -396,7 +396,7 @@ fail(undef, "Local and remote namespaces are neither both flat nor both hierarch fail(undef, "Local and remote hierachy delimiters differ ", "(local ", print_delimiter($IMAP->{local}->{delimiter}), ", ", "remote ", print_delimiter($IMAP->{remote}->{delimiter}), "), ", - "refusing to update \`mailboxes\` table.") + "refusing to update table \`mailboxes\`.") if defined $IMAP->{local}->{delimiter} and defined $IMAP->{remote}->{delimiter} # we failed earlier if only one of them was NIL and $IMAP->{local}->{delimiter} ne $IMAP->{remote}->{delimiter}; @@ -418,7 +418,7 @@ fail(undef, "Local and remote namespaces are neither both flat nor both hierarch $DBH->do("DROP TABLE mailboxes"); $DBH->do("ALTER TABLE _tmp${DATABASE_VERSION}_mailboxes RENAME TO mailboxes"); } - fail("database", "Broken referential integrity! Refusing to commit changes.") + fail("database", "Broken referential integrity! Refusing to commit changes.") if defined $DBH->selectrow_arrayref("PRAGMA foreign_key_check"); SCHEMA_DONE: $DBH->do("PRAGMA user_version = $DATABASE_VERSION"); @@ -530,6 +530,7 @@ if (defined $COMMAND and $COMMAND eq 'delete') { qw/mapping local remote mailboxes/ if @ARGV and $CONFIG{target}->{database}; foreach my $mailbox (@ARGV) { + fail(undef, "INBOX can't be deleted") if uc($mailbox) eq "INBOX"; # RFC 3501 sec. 6.3.4 my $idx = db_get_mailbox_idx($mailbox); # delete $mailbox on servers where $mailbox exists. note that diff --git a/tests/00-db-exclusive/local.conf b/tests/00-db-exclusive/local.conf deleted file mode 100644 index 9c838fd..0000000 --- a/tests/00-db-exclusive/local.conf +++ /dev/null @@ -1,5 +0,0 @@ -namespace inbox { - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/00-db-exclusive/remote.conf b/tests/00-db-exclusive/remote.conf deleted file mode 100644 index 9c838fd..0000000 --- a/tests/00-db-exclusive/remote.conf +++ /dev/null @@ -1,5 +0,0 @@ -namespace inbox { - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/00-db-exclusive/run b/tests/00-db-exclusive/run deleted file mode 100644 index 1528b3b..0000000 --- a/tests/00-db-exclusive/run +++ /dev/null @@ -1,25 +0,0 @@ -# verify that database isn't created in --watch mode -! interimap --watch=60 -xgrep -E "^DBI connect\(.*\) failed: unable to open database file at " <"$STDERR" - -# now create database -interimap - -# start a background process -interimap --watch=60 & pid=$! -cleanup() { - # kill interimap process and its children - pkill -P "$pid" -TERM || true - kill -TERM "$pid" || true - wait -} -trap cleanup EXIT INT TERM - -sleep .05 # wait a short while so we have time to lock the database (ugly and racy...) -# verify that subsequent runs fail as we can't acquire the exclusive lock -! interimap - -# line 177 is `$DBH->do("PRAGMA locking_mode = EXCLUSIVE");` -xgrep -Fx "DBD::SQLite::db do failed: database is locked at ./interimap line 177." <"$STDERR" - -# vim: set filetype=sh : diff --git a/tests/00-db-migration-0-to-1-delim-mismatch/before.sql b/tests/00-db-migration-0-to-1-delim-mismatch/before.sql deleted file mode 120000 index 0abb9bf..0000000 --- a/tests/00-db-migration-0-to-1-delim-mismatch/before.sql +++ /dev/null @@ -1 +0,0 @@ -../00-db-migration-0-to-1/before.sql
\ No newline at end of file diff --git a/tests/00-db-migration-0-to-1-delim-mismatch/local.conf b/tests/00-db-migration-0-to-1-delim-mismatch/local.conf deleted file mode 100644 index 08438cb..0000000 --- a/tests/00-db-migration-0-to-1-delim-mismatch/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = "\"" - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/00-db-migration-0-to-1-delim-mismatch/remote.conf b/tests/00-db-migration-0-to-1-delim-mismatch/remote.conf deleted file mode 100644 index cc6781d..0000000 --- a/tests/00-db-migration-0-to-1-delim-mismatch/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ^ - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/00-db-migration-0-to-1-delim-mismatch/run b/tests/00-db-migration-0-to-1-delim-mismatch/run deleted file mode 100644 index 434c678..0000000 --- a/tests/00-db-migration-0-to-1-delim-mismatch/run +++ /dev/null @@ -1,8 +0,0 @@ -# import an existing non-migrated database -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <"$TESTDIR/before.sql" -! interimap - -# may happen if the server(s) software or its configuration changed -xgrep -Fx 'ERROR: Local and remote hierachy delimiters differ (local "\"", remote "^"), refusing to update `mailboxes` table.' <"$STDERR" - -# vim: set filetype=sh : diff --git a/tests/00-db-migration-0-to-1-foreign-key-violation/local.conf b/tests/00-db-migration-0-to-1-foreign-key-violation/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/00-db-migration-0-to-1-foreign-key-violation/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/00-db-migration-0-to-1-foreign-key-violation/remote.conf b/tests/00-db-migration-0-to-1-foreign-key-violation/remote.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/00-db-migration-0-to-1-foreign-key-violation/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/00-db-migration-0-to-1-foreign-key-violation/run b/tests/00-db-migration-0-to-1-foreign-key-violation/run deleted file mode 100644 index f2d12a9..0000000 --- a/tests/00-db-migration-0-to-1-foreign-key-violation/run +++ /dev/null @@ -1,23 +0,0 @@ -# create new schema and add INBOX -interimap -xgrep "^Creating new schema in database file " <"$STDERR" -xgrep -Fx "database: Created mailbox INBOX" <"$STDERR" - -# empty table `mailboxes` and revert its schema to version 0 -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <<-EOF - PRAGMA foreign_keys = OFF; - PRAGMA user_version = 0; - DROP TABLE mailboxes; - CREATE TABLE mailboxes ( - idx INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - mailbox TEXT NOT NULL CHECK (mailbox != '') UNIQUE, - subscribed BOOLEAN NOT NULL - ); -EOF - -# check that migration fails due to broken referential integrity -! interimap -xgrep -Fx "Upgrading database version from 0" <"$STDERR" -xgrep -Fx "database: ERROR: Broken referential integrity! Refusing to commit changes." <"$STDERR" - -# vim: set filetype=sh : diff --git a/tests/00-db-migration-0-to-1/local.conf b/tests/00-db-migration-0-to-1/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/00-db-migration-0-to-1/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/00-db-migration-0-to-1/remote.conf b/tests/00-db-migration-0-to-1/remote.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/00-db-migration-0-to-1/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/01-rename-exists-db/local.conf b/tests/01-rename-exists-db/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/01-rename-exists-db/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/01-rename-exists-db/remote.conf b/tests/01-rename-exists-db/remote.conf deleted file mode 100644 index 61e3d0d..0000000 --- a/tests/01-rename-exists-db/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = "\\" - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/01-rename-exists-local/local.conf b/tests/01-rename-exists-local/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/01-rename-exists-local/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/01-rename-exists-local/remote.conf b/tests/01-rename-exists-local/remote.conf deleted file mode 100644 index 61e3d0d..0000000 --- a/tests/01-rename-exists-local/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = "\\" - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/01-rename-exists-remote/local.conf b/tests/01-rename-exists-remote/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/01-rename-exists-remote/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/01-rename-exists-remote/remote.conf b/tests/01-rename-exists-remote/remote.conf deleted file mode 100644 index 61e3d0d..0000000 --- a/tests/01-rename-exists-remote/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = "\\" - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/01-rename/local.conf b/tests/01-rename/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/01-rename/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/01-rename/remote.conf b/tests/01-rename/remote.conf deleted file mode 100644 index cc6781d..0000000 --- a/tests/01-rename/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ^ - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/02-delete/local.conf b/tests/02-delete/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/02-delete/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/02-delete/remote.conf b/tests/02-delete/remote.conf deleted file mode 100644 index cc6781d..0000000 --- a/tests/02-delete/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ^ - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/03-sync-mailbox-list-partial/interimap.conf b/tests/03-sync-mailbox-list-partial/interimap.conf deleted file mode 100644 index 4970867..0000000 --- a/tests/03-sync-mailbox-list-partial/interimap.conf +++ /dev/null @@ -1 +0,0 @@ -list-mailbox = * diff --git a/tests/03-sync-mailbox-list-partial/local.conf b/tests/03-sync-mailbox-list-partial/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/03-sync-mailbox-list-partial/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/03-sync-mailbox-list-partial/remote.conf b/tests/03-sync-mailbox-list-partial/remote.conf deleted file mode 100644 index 352cdd4..0000000 --- a/tests/03-sync-mailbox-list-partial/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ~ - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/03-sync-mailbox-list-partial/run b/tests/03-sync-mailbox-list-partial/run deleted file mode 100644 index 449115d..0000000 --- a/tests/03-sync-mailbox-list-partial/run +++ /dev/null @@ -1,57 +0,0 @@ -# try a bunch of invalid 'list-mailbox' values: -# empty string, missing space between values, unterminated string -for v in '""' '"f o o""bar"' '"f o o" "bar" "baz\" x'; do - sed -ri "s/^(list-mailbox\\s*=\\s*).*/\\1${v//\\/\\\\}/" "$XDG_CONFIG_HOME/interimap/config" - ! interimap - xgrep -xF "Invalid value for list-mailbox: $v" <"$STDERR" -done - -# create some mailboxes -doveadm -u "local" mailbox create "foo" "foo bar" "f\\\"o!o.bar" "f.o.o" "bad" -for m in "foo" "foo bar" "f\\\"o!o.bar" "f.o.o" "bad" "INBOX"; do - sample_message | deliver -u "local" -- -m "$m" -done - -# restrict 'list-mailbox' to the above minus "bad" -sed -ri 's/^(list-mailbox\s*=\s*).*/\1foo "foo bar" "f\\\\\\"o\\x21o.*" "f\\0o\\0o"/' \ - "$XDG_CONFIG_HOME/interimap/config" - -# run partial sync -interimap -check_mailbox_list "foo" "foo bar" "f\\\"o!o.bar" "f.o.o" "INBOX" "f\\\"o!o" "f" "f.o" -check_mailboxes_status "foo" "foo bar" "f\\\"o!o.bar" "f.o.o" - -# check that "bad" isn't in the remote imap server -! doveadm -u "remote" mailbox status uidvalidity "bad" - -# check that "bad" and "INBOX" aren't in the database -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/count" <<-EOF - SELECT COUNT(*) - FROM mailboxes - WHERE mailbox = x'$(printf "%s" "bad" | xxd -ps)' - OR mailbox = x'$(printf "%s" "INBOX" | xxd -ps)' -EOF -[ $(< "$TMPDIR/count") -eq 0 ] - - -# run partial sync -doveadm -u "remote" mailbox create "f\\\"o!o~baz" "f\\\"o!o~bad" -for m in "f\\\"o!o~baz" "f\\\"o!o~bad"; do - sample_message | deliver -u "remote" -- -m "$m" -done -interimap "f\\\"o!o.baz" - -check_mailbox_list "foo" "foo bar" "f\\\"o!o.bar" "f.o.o" "INBOX" "f\\\"o!o" "f" "f.o" "f\\\"o!o.baz" -check_mailboxes_status "foo" "foo bar" "f\\\"o!o.bar" "f.o.o" "f\\\"o!o.baz" - -# check that "bad", "f\\\"o!o.bad" and "INBOX" aren't in the database -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/count" <<-EOF - SELECT COUNT(*) - FROM mailboxes - WHERE mailbox = x'$(printf "%s" "bad" | xxd -ps)' - OR mailbox = x'$(printf "%s" "INBOX" | xxd -ps)' - OR mailbox = x'$(printf "%s\\0%s" "f\\\"o!o" "bad" | xxd -ps)' -EOF -[ $(< "$TMPDIR/count") -eq 0 ] - -# vim: set filetype=sh : diff --git a/tests/03-sync-mailbox-list-ref/local.conf b/tests/03-sync-mailbox-list-ref/local.conf deleted file mode 100644 index 6eccf43..0000000 --- a/tests/03-sync-mailbox-list-ref/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = / - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/03-sync-mailbox-list-ref/remote.conf b/tests/03-sync-mailbox-list-ref/remote.conf deleted file mode 100644 index 61e3d0d..0000000 --- a/tests/03-sync-mailbox-list-ref/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = "\\" - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/03-sync-mailbox-list-ref/run b/tests/03-sync-mailbox-list-ref/run deleted file mode 100644 index 3ead25d..0000000 --- a/tests/03-sync-mailbox-list-ref/run +++ /dev/null @@ -1,28 +0,0 @@ -# Note: implementation-dependent as the reference name is not a level of -# mailbox hierarchy nor ends with the hierarchy delimiter -sed -ri 's#^\[local\]$#&\nlist-reference = foo#; s#^\[remote\]$#&\nlist-reference = bar#' \ - "$XDG_CONFIG_HOME/interimap/config" - -# create a bunch of mailboxes in and out the respective list # references -doveadm -u "local" mailbox create "foo" "foobar" "foo/bar/baz" "foo/baz" "bar" -doveadm -u "remote" mailbox create "foo" - -# deliver somemessages to these mailboxes -for m in "foo" "foobar" "foo/bar/baz" "foo/baz" "bar"; do - sample_message | deliver -u "local" -- -m "$m" -done -sample_message | deliver -u "remote" -- -m "foo" - -interimap - -# check that the mailbox lists match -diff -u --label="local/mailboxes" --label="remote/mailboxes" \ - <( doveadm -u "local" mailbox list | sed -n "s/^foo//p" | sort ) \ - <( doveadm -u "remote" mailbox list | sed -n "s/^bar//p" | tr '\\' '/' | sort ) - -for m in "" "bar" "/bar/baz" "/baz"; do - blob="x'$(printf "%s" "$m" | tr "/" "\\0" | xxd -c256 -ps)'" - check_mailbox_status2 "$blob" "foo$m" "remote" "bar${m//\//\\}" -done - -# vim: set filetype=sh : diff --git a/tests/03-sync-mailbox-list/local.conf b/tests/03-sync-mailbox-list/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/03-sync-mailbox-list/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/03-sync-mailbox-list/remote.conf b/tests/03-sync-mailbox-list/remote.conf deleted file mode 100644 index 352cdd4..0000000 --- a/tests/03-sync-mailbox-list/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ~ - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/03-sync-mailbox-list/run b/tests/03-sync-mailbox-list/run deleted file mode 100644 index b506204..0000000 --- a/tests/03-sync-mailbox-list/run +++ /dev/null @@ -1,73 +0,0 @@ -# pre-create some mailboxes and susbscribe to some -# foo: present on both, subscribed to both -# bar: present on both, subscribed to local only -# baz: present on both, subscribed to remote only -# foo.bar: present on local only -# foo.baz: present on remote only -doveadm -u "local" mailbox create "foo" "bar" "baz" "foo.bar" "fo!o [b*a%r]" -doveadm -u "local" mailbox subscribe "foo" "bar" -doveadm -u "remote" mailbox create "foo" "bar" "baz" "foo~baz" "foo]bar" -doveadm -u "remote" mailbox subscribe "foo" "baz" - -interimap -xgrep -Fx "local: Subscribe to baz" <"$STDERR" -xgrep -Fx "remote: Subscribe to bar" <"$STDERR" -xgrep -Fx "local: Created mailbox foo.baz" <"$STDERR" -xgrep -Fx "remote: Created mailbox foo~bar" <"$STDERR" - -# check syncing -check_mailbox_list -check_mailboxes_status "foo" "bar" "baz" "foo.bar" "foo.baz" "INBOX" "fo!o [b*a%r]" "foo]bar" -check_mailbox_list -s - - -# delete a mailbox one server and verify that synchronization fails as it's still in the database -doveadm -u "remote" mailbox delete "foo~baz" -! interimap -xgrep -Fx 'database: ERROR: Mailbox foo.baz exists. Run `interimap --target=database --delete foo.baz` to delete.' <"$STDERR" -interimap --target="database" --delete "foo.baz" -xgrep -Fx 'database: Removed mailbox foo.baz' <"$STDERR" -interimap # create again -xgrep -Fx 'database: Created mailbox foo.baz' <"$STDERR" -xgrep -Fx 'remote: Created mailbox foo~baz' <"$STDERR" - -doveadm -u "local" mailbox delete "foo.bar" -! interimap -xgrep -Fx 'database: ERROR: Mailbox foo.bar exists. Run `interimap --target=database --delete foo.bar` to delete.' <"$STDERR" -interimap --target="database" --delete "foo.bar" -xgrep -Fx 'database: Removed mailbox foo.bar' <"$STDERR" -interimap -xgrep -Fx 'database: Created mailbox foo.bar' <"$STDERR" -xgrep -Fx 'local: Created mailbox foo.bar' <"$STDERR" - -check_mailbox_list -check_mailboxes_status "foo" "bar" "baz" "foo.bar" "foo.baz" "INBOX" "fo!o [b*a%r]" "foo]bar" -check_mailbox_list -s - - -# (un)subscribe from some mailboxes, including a non-existent one -doveadm -u "local" mailbox unsubscribe "foo" -doveadm -u "remote" mailbox unsubscribe "bar" -doveadm -u "local" mailbox subscribe "foo.bar" "foo.nonexistent" "foo.baz" -doveadm -u "remote" mailbox subscribe "foo~bar" "bar~nonexistent" - -interimap -xgrep -Fx 'remote: Unsubscribe to foo' <"$STDERR" -xgrep -Fx 'local: Unsubscribe to bar' <"$STDERR" -xgrep -Fx 'remote: Subscribe to foo~baz' <"$STDERR" -check_mailbox_list -check_mailbox_list -s $(doveadm -u "local" mailbox list) # exclude "foo.nonexistent" and "bar~nonexistent" - -# check that "baz", "foo.bar" and "foo.baz" are the only subscribed mailboxes -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/count" <<-EOF - SELECT COUNT(*) - FROM mailboxes - WHERE subscribed <> (mailbox IN ( - x'$(printf "%s" "baz" | xxd -ps)', - x'$(printf "%s\\0%s" "foo" "bar" | xxd -ps)', - x'$(printf "%s\\0%s" "foo" "baz" | xxd -ps)' - )) -EOF -[ $(< "$TMPDIR/count") -eq 0 ] - -# vim: set filetype=sh : diff --git a/tests/04-resume/local.conf b/tests/04-resume/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/04-resume/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/04-resume/remote.conf b/tests/04-resume/remote.conf deleted file mode 100644 index 352cdd4..0000000 --- a/tests/04-resume/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ~ - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/05-repair/local.conf b/tests/05-repair/local.conf deleted file mode 100644 index 93497d9..0000000 --- a/tests/05-repair/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/05-repair/remote.conf b/tests/05-repair/remote.conf deleted file mode 100644 index 352cdd4..0000000 --- a/tests/05-repair/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ~ - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/06-largeint/local.conf b/tests/06-largeint/local.conf deleted file mode 100644 index 9c838fd..0000000 --- a/tests/06-largeint/local.conf +++ /dev/null @@ -1,5 +0,0 @@ -namespace inbox { - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/06-largeint/remote.conf b/tests/06-largeint/remote.conf deleted file mode 100644 index 9c838fd..0000000 --- a/tests/06-largeint/remote.conf +++ /dev/null @@ -1,5 +0,0 @@ -namespace inbox { - location = maildir:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/07-sync-live-multi/remote.conf b/tests/07-sync-live-multi/remote.conf deleted file mode 100644 index 3267182..0000000 --- a/tests/07-sync-live-multi/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ^ - location = dbox:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/07-sync-live-multi/remote2.conf b/tests/07-sync-live-multi/remote2.conf deleted file mode 100644 index 062429e..0000000 --- a/tests/07-sync-live-multi/remote2.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = "\\" - location = dbox:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/07-sync-live-multi/remote3.conf b/tests/07-sync-live-multi/remote3.conf deleted file mode 100644 index a4b9b1c..0000000 --- a/tests/07-sync-live-multi/remote3.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = "?" - location = dbox:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/07-sync-live/local.conf b/tests/07-sync-live/local.conf deleted file mode 100644 index 1333540..0000000 --- a/tests/07-sync-live/local.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = . - location = dbox:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/07-sync-live/remote.conf b/tests/07-sync-live/remote.conf deleted file mode 100644 index 3267182..0000000 --- a/tests/07-sync-live/remote.conf +++ /dev/null @@ -1,6 +0,0 @@ -namespace inbox { - separator = ^ - location = dbox:~/inbox:LAYOUT=index - inbox = yes - list = yes -} diff --git a/tests/db-exclusive-lock/t b/tests/db-exclusive-lock/t new file mode 100644 index 0000000..88172c9 --- /dev/null +++ b/tests/db-exclusive-lock/t @@ -0,0 +1,16 @@ +interimap_init + +# start a background process +interimap --watch=60 & +trap "ptree_abort $!" EXIT INT TERM + +# wait a short while so we have time to lock the database (ugly and racy...) +sleep .5 + +# subsequent runs fail as we can't acquire the exclusive lock +! interimap || error + +grep -Fx "DBD::SQLite::db do failed: database is locked at ./interimap line 177." <"$STDERR" \ + || error "Is \$DBH->do(\"PRAGMA locking_mode = EXCLUSIVE\"); at line 177?" + +# vim: set filetype=sh : diff --git a/tests/db-migration-0-1-foreign-key-violation/t b/tests/db-migration-0-1-foreign-key-violation/t new file mode 100644 index 0000000..35e5be5 --- /dev/null +++ b/tests/db-migration-0-1-foreign-key-violation/t @@ -0,0 +1,21 @@ +interimap_init +grep -Fx "database: Created mailbox INBOX" <"$STDERR" || error "INBOX missing from DB" + +# empty table `mailboxes` and revert its schema to version 0 +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <<-EOF + PRAGMA foreign_keys = OFF; + PRAGMA user_version = 0; + DROP TABLE mailboxes; + CREATE TABLE mailboxes ( + idx INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + mailbox TEXT NOT NULL CHECK (mailbox != '') UNIQUE, + subscribed BOOLEAN NOT NULL + ); +EOF + +# now migration must fail due to broken referential integrity +! interimap || error +grep -Fx "Upgrading database version from 0" <"$STDERR" || error "DB upgrade not attempted" +grep -Fx "database: ERROR: Broken referential integrity! Refusing to commit changes." <"$STDERR" || error "DB upgrade successful despite broken refint" + +# vim: set filetype=sh : diff --git a/tests/db-no-create--watch/t b/tests/db-no-create--watch/t new file mode 100644 index 0000000..89f1e3e --- /dev/null +++ b/tests/db-no-create--watch/t @@ -0,0 +1,6 @@ +! interimap --watch=60 || error + +grep -Ex "DBI connect\(.*\) failed: unable to open database file at \./interimap line 173\." <"$STDERR" || error +test \! -e "$XDG_DATA_HOME/interimap/remote.db" || error + +# vim: set filetype=sh : diff --git a/tests/db-upgrade-0-1-delim-mismatch/before.sql b/tests/db-upgrade-0-1-delim-mismatch/before.sql new file mode 120000 index 0000000..6c31715 --- /dev/null +++ b/tests/db-upgrade-0-1-delim-mismatch/before.sql @@ -0,0 +1 @@ +../db-upgrade-0-1/before.sql
\ No newline at end of file diff --git a/tests/db-upgrade-0-1-delim-mismatch/local.conf b/tests/db-upgrade-0-1-delim-mismatch/local.conf new file mode 100644 index 0000000..900c73f --- /dev/null +++ b/tests/db-upgrade-0-1-delim-mismatch/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = "\"" +} diff --git a/tests/db-upgrade-0-1-delim-mismatch/remote.conf b/tests/db-upgrade-0-1-delim-mismatch/remote.conf new file mode 100644 index 0000000..2d08a24 --- /dev/null +++ b/tests/db-upgrade-0-1-delim-mismatch/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ^ +} diff --git a/tests/db-upgrade-0-1-delim-mismatch/t b/tests/db-upgrade-0-1-delim-mismatch/t new file mode 100644 index 0000000..d133437 --- /dev/null +++ b/tests/db-upgrade-0-1-delim-mismatch/t @@ -0,0 +1,7 @@ +# import an existing non-migrated database +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <"$TESTDIR/before.sql" || error "Couldn't import DB" +! interimap || error + +grep -Fx 'ERROR: Local and remote hierachy delimiters differ (local "\"", remote "^"), refusing to update table `mailboxes`.' <"$STDERR" || error + +# vim: set filetype=sh : diff --git a/tests/00-db-migration-0-to-1/after.sql b/tests/db-upgrade-0-1/after.sql index 18b0ad7..18b0ad7 100644 --- a/tests/00-db-migration-0-to-1/after.sql +++ b/tests/db-upgrade-0-1/after.sql diff --git a/tests/00-db-migration-0-to-1/before.sql b/tests/db-upgrade-0-1/before.sql index 333a1dc..333a1dc 100644 --- a/tests/00-db-migration-0-to-1/before.sql +++ b/tests/db-upgrade-0-1/before.sql diff --git a/tests/db-upgrade-0-1/local.conf b/tests/db-upgrade-0-1/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/db-upgrade-0-1/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/db-upgrade-0-1/remote.conf b/tests/db-upgrade-0-1/remote.conf new file mode 120000 index 0000000..b798ff5 --- /dev/null +++ b/tests/db-upgrade-0-1/remote.conf @@ -0,0 +1 @@ +local.conf
\ No newline at end of file diff --git a/tests/00-db-migration-0-to-1/run b/tests/db-upgrade-0-1/t index 757fe04..088008e 100644 --- a/tests/00-db-migration-0-to-1/run +++ b/tests/db-upgrade-0-1/t @@ -1,14 +1,14 @@ -# create some mailboxes +# create the mailboxes from the database doveadm -u "local" mailbox create "a.b1.c1" "a.b1.c2" "a.b2.c" "a2" doveadm -u "remote" mailbox create "a.b1.c1" "a.b1.c2" "a.b2.c" "a2" # import an existing non-migrated database -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <"$TESTDIR/before.sql" +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" <"$TESTDIR/before.sql" || error "Couldn't import DB" # migrate -interimap +interimap || error "Couldn't upgrade DB" -xgrep -Fx "Upgrading database version from 0" <"$STDERR" +grep -Fx "Upgrading database version from 0" <"$STDERR" || error "Couldn't upgrade DB" check_mailboxes_status "a.b1.c1" "a.b1.c2" "a.b2.c" "a2" # verify that the new schema is as expected @@ -28,6 +28,7 @@ EOF # XXX need 'user_version' PRAGMA in the dump for future migrations # http://sqlite.1065341.n5.nabble.com/dump-command-and-user-version-td101228.html diff -u --label="a/dump.sql" --label="b/dump.sql" \ - "$TMPDIR/dump-expected.sql" "$TMPDIR/dump.sql" + "$TMPDIR/dump-expected.sql" "$TMPDIR/dump.sql" \ + || error "DB dumps differ" # vim: set filetype=sh : diff --git a/tests/delete/local.conf b/tests/delete/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/delete/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/delete/remote.conf b/tests/delete/remote.conf new file mode 100644 index 0000000..2d08a24 --- /dev/null +++ b/tests/delete/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ^ +} diff --git a/tests/02-delete/run b/tests/delete/t index f63c52c..c38d4d3 100644 --- a/tests/02-delete/run +++ b/tests/delete/t @@ -4,15 +4,16 @@ for m in "foo.bar" "foo.bar.baz" "INBOX"; do sample_message | deliver -u "local" -- -m "$m" done -interimap +interimap_init check_mailbox_list check_mailboxes_status "foo.bar" "foo.bar.baz" "INBOX" sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump.sql" <<-EOF .dump EOF -# delete non-existent mailbox is a no-op -interimap --target="local,remote" --target="database" --delete "nonexistent" + +step_start "nonexistent source (no-op)" +interimap --target="local,remote" --target="database" --delete "nonexistent" || error check_mailbox_list check_mailboxes_status "foo.bar" "foo.bar.baz" "INBOX" @@ -20,13 +21,22 @@ sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump2.sql" <<-EOF .dump EOF diff -u --label="a/dump.sql" --label="b/dump.sql" \ - "$TMPDIR/dump.sql" "$TMPDIR/dump2.sql" + "$TMPDIR/dump.sql" "$TMPDIR/dump2.sql" || error "SQL dumps differ" +step_done + # foo.bar will become \NoSelect in local, per RFC 3501: "It is permitted # to delete a name that has inferior hierarchical names and does not # have the \Noselect mailbox name attribute. In this case, all messages # in that mailbox are removed, and the name will acquire the \Noselect # mailbox name attribute." +step_start "mailbox with inferiors" +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes.sql" <<-EOF + SELECT idx, mailbox FROM mailboxes + WHERE mailbox != x'$(printf "%s\\0%s" "foo" "bar" | xxd -ps)' + ORDER BY idx +EOF + interimap --target="local" --delete "foo.bar" check_mailbox_list @@ -35,33 +45,51 @@ check_mailboxes_status "foo.bar.baz" "INBOX" sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump2.sql" <<-EOF .dump EOF -diff -u --label="a/dump.sql" --label="b/dump.sql" "$TMPDIR/dump.sql" "$TMPDIR/dump2.sql" +diff -u --label="a/dump.sql" --label="b/dump.sql" \ + "$TMPDIR/dump.sql" "$TMPDIR/dump2.sql" || error "SQL dumps differ" ! doveadm -u "local" mailbox status uidvalidity "foo.bar" # gone doveadm -u "remote" mailbox status uidvalidity "foo^bar" -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes.csv" <<-EOF - SELECT idx, mailbox - FROM mailboxes - WHERE mailbox != x'$(printf "%s\\0%s" "foo" "bar" | xxd -ps)' -EOF - - # now delete from the remote server and the database interimap --delete "foo.bar" ! doveadm -u "local" mailbox status uidvalidity "foo.bar" ! doveadm -u "remote" mailbox status uidvalidity "foo^bar" -sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes2.csv" <<-EOF - SELECT idx, mailbox - FROM mailboxes - WHERE mailbox != x'$(printf "%s\\0%s" "foo" "bar" | xxd -ps)' +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes2.sql" <<-EOF + SELECT idx, mailbox FROM mailboxes ORDER BY idx EOF -diff -u --label="a/mailboxes.csv" --label="b/mailboxes.csv" \ - "$TMPDIR/mailboxes.csv" "$TMPDIR/mailboxes2.csv" +diff -u --label="a/mailboxes.sql" --label="b/mailboxes.sql" \ + "$TMPDIR/mailboxes.sql" "$TMPDIR/mailboxes2.sql" || error "SQL dumps differ" check_mailbox_list check_mailboxes_status "foo.bar.baz" "INBOX" +step_done + + +step_start "INBOX (fail)" +! interimap --delete "InBoX" || error "deleted INBOX" +grep -Fx "ERROR: INBOX can't be deleted" <"$STDERR" || error + +check_mailbox_list +check_mailboxes_status "foo.bar.baz" "INBOX" +step_done + + +step_start "\\Noinferiors mailbox" +interimap --delete "foo.bar.baz" + +! doveadm -u "local" mailbox status uidvalidity "foo.bar.baz" +! doveadm -u "remote" mailbox status uidvalidity "foo^bar^baz" + +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/count" <<-EOF + SELECT COUNT(*) FROM mailboxes +EOF +[ "$(< "$TMPDIR/count" )" -eq 1 ] || error "Not only INBOX left?" + +check_mailbox_list +check_mailboxes_status "INBOX" +step_done # vim: set filetype=sh : diff --git a/tests/ignore-mailbox/interimap.conf b/tests/ignore-mailbox/interimap.conf new file mode 100644 index 0000000..6168958 --- /dev/null +++ b/tests/ignore-mailbox/interimap.conf @@ -0,0 +1 @@ +ignore-mailbox = ^virtual(?:\x00|$) diff --git a/tests/ignore-mailbox/local.conf b/tests/ignore-mailbox/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/ignore-mailbox/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/ignore-mailbox/remote.conf b/tests/ignore-mailbox/remote.conf new file mode 100644 index 0000000..2d08a24 --- /dev/null +++ b/tests/ignore-mailbox/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ^ +} diff --git a/tests/ignore-mailbox/t b/tests/ignore-mailbox/t new file mode 100644 index 0000000..f90227c --- /dev/null +++ b/tests/ignore-mailbox/t @@ -0,0 +1,62 @@ +doveadm -u "local" mailbox create "foo" -- "-virtual" +doveadm -u "remote" mailbox create "bar" -- "virtual-" + +interimap_init +check_mailbox_list + +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes.sql" <<-EOF + SELECT idx, mailbox FROM mailboxes ORDER BY idx +EOF + +for ((i = 0; i < 16; i++)); do + u="$(shuf -n1 -e "local" "remote")" # choose target at random + m="$(shuf -n1 -e -- "INBOX" "foo" "bar")" + sample_message | deliver -u "$u" -- -m "$m" +done + +# create new mailboxes matching 'ignore-mailbox' +doveadm -u "local" mailbox create "virtual" "virtual.foo" +doveadm -u "remote" mailbox create "virtual^bar" +for n in $(seq 1 "$(shuf -n1 -i1-8)"); do + sample_message | deliver -u "local" -- -m "virtual" + sample_message | deliver -u "local" -- -m "virtual.foo" +done +for n in $(seq 1 "$(shuf -n1 -i1-8)"); do + sample_message | deliver -u "remote" -- -m "virtual^bar" +done + + +# no new mailbox should be created +interimap || error + +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes2.sql" <<-EOF + SELECT idx, mailbox FROM mailboxes ORDER BY idx +EOF +diff -u --label="a/mailboxes.sql" --label="b/mailboxes.sql" \ + "$TMPDIR/mailboxes.sql" "$TMPDIR/mailboxes2.sql" || error "SQL dumps differ" + +check_mailboxes_status "INBOX" "foo" "bar" + +# double check the unsubscribed mailboxes weren't copied +! doveadm -u "remote" mailbox status uidvalidity "virtual" || error +! doveadm -u "remote" mailbox status uidvalidity "virtual^foo" || error +! doveadm -u "local" mailbox status uidvalidity "virtual.bar" || error + + +# ignored mailboxes are created when passed to the command line +interimap "virtual" "virtual.bar" || error +grep -Fx "database: Created mailbox virtual" <"$STDERR" || error +grep -Fx "database: Created mailbox virtual.bar" <"$STDERR" || error +grep -Fx "local: Created mailbox virtual.bar" <"$STDERR" || error +grep -Fx "remote: Created mailbox virtual" <"$STDERR" || error + +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes.sql" <<-EOF + SELECT idx, mailbox FROM mailboxes + WHERE mailbox != x'$(printf "virtual" | xxd -ps)' + AND mailbox != x'$(printf "%s\\0%s" "virtual" "foo" | xxd -ps)' + ORDER BY idx +EOF + +check_mailboxes_status "virtual" "virtual.bar" || error + +# vim: set filetype=sh : diff --git a/tests/06-largeint/run b/tests/largeint/t index b08bcfa..b0877d5 100644 --- a/tests/06-largeint/run +++ b/tests/largeint/t @@ -12,13 +12,14 @@ doveadm -u "remote" mailbox update --uid-validity 2147483647 "bar" # 2^31-1 doveadm -u "remote" mailbox update --uid-validity 1 "baz" # run() { - local u m - for u in local remote; do - for m in "INBOX" "foo" "bar" "baz"; do - sample_message | deliver -u "$u" -- -m "$m" - done + local u m i + for ((i = 0; i < 64; i++)); do + u="$(shuf -n1 -e "local" "remote")" # choose target at random + m="$(shuf -n1 -e -- "INBOX" "foo" "bar" "baz")" + sample_message | deliver -u "$u" -- -m "$m" done - interimap + interimap || error + check_mailbox_list check_mailbox_status "INBOX" "foo" "bar" "baz" } run diff --git a/tests/list b/tests/list new file mode 100644 index 0000000..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/01-rename-exists-db/run b/tests/rename-exists-db/t index aad7c44..cb6cfcd 100644 --- a/tests/01-rename-exists-db/run +++ b/tests/rename-exists-db/t @@ -1,14 +1,14 @@ doveadm -u "local" mailbox create "root.from" "root.from.child" "t.o" doveadm -u "remote" mailbox create "root\\from" "root\\from\\child" "t\\o" -interimap +interimap_init check_mailbox_list # delete a mailbox on both servers but leave it in the database, then try to use it as target for --rename doveadm -u "local" mailbox delete "t.o" doveadm -u "remote" mailbox delete "t\\o" -! interimap --rename "root.from" "t.o" -xgrep -Fx 'database: ERROR: Mailbox t.o exists. Run `interimap --target=database --delete t.o` to delete.' <"$STDERR" +! interimap --rename "root.from" "t.o" || error +grep -Fx 'database: ERROR: Mailbox t.o exists. Run `interimap --target=database --delete t.o` to delete.' <"$STDERR" || error # vim: set filetype=sh : diff --git a/tests/rename-exists-local/local.conf b/tests/rename-exists-local/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/rename-exists-local/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/rename-exists-local/remote.conf b/tests/rename-exists-local/remote.conf new file mode 100644 index 0000000..9657e89 --- /dev/null +++ b/tests/rename-exists-local/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = "\\" +} diff --git a/tests/01-rename-exists-local/run b/tests/rename-exists-local/t index d82a0a4..190f49a 100644 --- a/tests/01-rename-exists-local/run +++ b/tests/rename-exists-local/t @@ -1,13 +1,13 @@ doveadm -u "local" mailbox create "root.from" "root.from.child" "t.o" doveadm -u "remote" mailbox create "root\\from" "root\\from\\child" -interimap +interimap_init check_mailbox_list # delete a mailbox on the remote server, then try to use it as target for --rename doveadm -u "remote" mailbox delete "t\\o" -! interimap --rename "root.from" "t.o" -xgrep -Fx 'local: ERROR: Mailbox t.o exists. Run `interimap --target=local --delete t.o` to delete.' <"$STDERR" +! interimap --rename "root.from" "t.o" || error +grep -Fx 'local: ERROR: Mailbox t.o exists. Run `interimap --target=local --delete t.o` to delete.' <"$STDERR" || error # vim: set filetype=sh : diff --git a/tests/rename-exists-remote/local.conf b/tests/rename-exists-remote/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/rename-exists-remote/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/rename-exists-remote/remote.conf b/tests/rename-exists-remote/remote.conf new file mode 100644 index 0000000..9657e89 --- /dev/null +++ b/tests/rename-exists-remote/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = "\\" +} diff --git a/tests/01-rename-exists-remote/run b/tests/rename-exists-remote/t index 28af1fc..be16a12 100644 --- a/tests/01-rename-exists-remote/run +++ b/tests/rename-exists-remote/t @@ -1,13 +1,13 @@ doveadm -u "local" mailbox create "root.from" "root.from.child" "t.o" doveadm -u "remote" mailbox create "root\\from" "root\\from\\child" "t\\o" -interimap +interimap_init check_mailbox_list # delete a mailbox on the local server, then try to use it as target for --rename doveadm -u "local" mailbox delete "t.o" -! interimap --rename "root.from" "t.o" -xgrep -Fx 'remote: ERROR: Mailbox t\o exists. Run `interimap --target=remote --delete t.o` to delete.' <"$STDERR" +! interimap --rename "root.from" "t.o" || error +grep -Fx 'remote: ERROR: Mailbox t\o exists. Run `interimap --target=remote --delete t.o` to delete.' <"$STDERR" || remote # vim: set filetype=sh : diff --git a/tests/rename-inferiors/local.conf b/tests/rename-inferiors/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/rename-inferiors/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/rename-inferiors/remote.conf b/tests/rename-inferiors/remote.conf new file mode 100644 index 0000000..2d08a24 --- /dev/null +++ b/tests/rename-inferiors/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ^ +} diff --git a/tests/01-rename/run b/tests/rename-inferiors/t index 6541c5c..9267e6f 100644 --- a/tests/01-rename/run +++ b/tests/rename-inferiors/t @@ -8,7 +8,7 @@ for m in "root^sibbling" "root^sibbling^grandchild" "root2" "INBOX"; do sample_message | deliver -u "remote" -- -m "$m" done -interimap +interimap_init check_mailboxes_status "root.from" "root.from.child" "root.from.child2" "root.from.child.grandchild" \ "root.sibbling" "root.sibbling.grandchild" "root2" "INBOX" sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes.csv" <<-EOF @@ -18,26 +18,31 @@ sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes.csv" <<-EOF ORDER BY idx EOF -# renaming a non-existent mailbox doesn't yield an error -interimap --rename "nonexistent" "nonexistent2" +step_start "non-existent source (no-op)" +interimap --rename "nonexistent" "root" || error "Renamed non-existent mailbox?" +check_mailbox_list +step_done + +step_start "\\NonExistent target (fail)" +! interimap --rename "root2" "root" || error "Didn't abort on ALREADYEXISTS" +grep -E "^local: ERROR: Couldn't rename mailbox root2: NO \[ALREADYEXISTS\] " <"$STDERR" check_mailbox_list +step_done -# renaming to an existing name yields an error -! interimap --rename "root2" "root" -xgrep -E "^local: ERROR: Couldn't rename mailbox root2: NO \[ALREADYEXISTS\] .*" <"$STDERR" # rename 'root.from' to 'from.root', including inferiors +step_start "existing source with inferiors" interimap --rename "root.from" "from.root" -xgrep -Fx 'local: Renamed mailbox root.from to from.root' <"$STDERR" -xgrep -Fx 'remote: Renamed mailbox root^from to from^root' <"$STDERR" -xgrep -Fx 'database: Renamed mailbox root.from to from.root' <"$STDERR" +grep -Fx 'local: Renamed mailbox root.from to from.root' <"$STDERR" +grep -Fx 'remote: Renamed mailbox root^from to from^root' <"$STDERR" +grep -Fx 'database: Renamed mailbox root.from to from.root' <"$STDERR" check_mailbox_list check_mailboxes_status "from.root" "from.root.child" "from.root.child2" "from.root.child.grandchild" \ "root.sibbling" "root.sibbling.grandchild" "root2" "INBOX" before="$(printf "%s\\0%s" "root" "from" | xxd -u -ps)" -after="$(printf "%s\\0%s" "from" "root" | xxd -ps)" +after="$(printf "%s\\0%s" "from" "root" | xxd -u -ps)" sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes2.csv" <<-EOF .mode csv SELECT idx, @@ -50,21 +55,24 @@ sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes2.csv" <<-EOF ORDER BY idx EOF diff -u --label="a/mailboxes.csv" --label="b/mailboxes.csv" \ - "$TMPDIR/mailboxes.csv" "$TMPDIR/mailboxes2.csv" + "$TMPDIR/mailboxes.csv" "$TMPDIR/mailboxes2.csv" \ + || error "Mailbox list differs" +step_done -# Try to rename \NonExistent root and check that its children move +# rename \NonExistent root and check that its children move +step_start "\\NonExistent source with inferiors" interimap --rename "root" "newroot" -xgrep -Fq 'local: Renamed mailbox root to newroot' <"$STDERR" -xgrep -Fq 'remote: Renamed mailbox root to newroot' <"$STDERR" -xgrep -Fq 'database: Renamed mailbox root to newroot' <"$STDERR" +grep -Fq 'local: Renamed mailbox root to newroot' <"$STDERR" +grep -Fq 'remote: Renamed mailbox root to newroot' <"$STDERR" +grep -Fq 'database: Renamed mailbox root to newroot' <"$STDERR" check_mailbox_list check_mailboxes_status "from.root" "from.root.child" "from.root.child2" "from.root.child.grandchild" \ "newroot.sibbling" "newroot.sibbling.grandchild" "root2" "INBOX" before2="$(printf "%s" "root" | xxd -u -ps)" -after2="$(printf "%s" "newroot" | xxd -ps)" +after2="$(printf "%s" "newroot" | xxd -u -ps)" sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes3.csv" <<-EOF .mode csv SELECT idx, @@ -79,6 +87,14 @@ sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes3.csv" <<-EOF ORDER BY idx EOF diff -u --label="a/mailboxes.csv" --label="b/mailboxes.csv" \ - "$TMPDIR/mailboxes2.csv" "$TMPDIR/mailboxes3.csv" + "$TMPDIR/mailboxes2.csv" "$TMPDIR/mailboxes3.csv" \ + || error "Mailbox list differs" +step_done + + +interimap +check_mailbox_list +check_mailboxes_status "from.root" "from.root.child" "from.root.child2" "from.root.child.grandchild" \ + "newroot.sibbling" "newroot.sibbling.grandchild" "root2" "INBOX" # vim: set filetype=sh : diff --git a/tests/rename-simple/t b/tests/rename-simple/t new file mode 100644 index 0000000..6ebee9a --- /dev/null +++ b/tests/rename-simple/t @@ -0,0 +1,61 @@ +doveadm -u "local" mailbox create "foo" + +sample_message | deliver -u "local" -- -m "INBOX" +sample_message | deliver -u "remote" -- -m "INBOX" +sample_message | deliver -u "remote" -- -m "foo" + +interimap_init + +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes.csv" <<-EOF + .mode csv + SELECT idx, hex(mailbox) + FROM mailboxes + ORDER BY idx +EOF + +step_start "non-existent source (no-op)" +interimap --rename "nonexistent" "bar" || error "Rename non-existent mailbox?" +check_mailbox_list +step_done + +step_start "existing target (fail)" +! interimap --rename "nonexistent" "foo" || error "Overwrote target?" +grep -Fx "local: ERROR: Mailbox foo exists. Run \`interimap --target=local --delete foo\` to delete." <"$STDERR" || error +check_mailbox_list +step_done + +step_start "INBOX" +interimap --rename "INBOX" "baz" || error +check_mailbox_list +step_done + +step_start "\\Noinferiors mailbox" +interimap --rename "foo" "bar" || error +check_mailbox_list + +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/mailboxes2.csv" <<-EOF + .mode csv + SELECT idx, + CASE + WHEN mailbox = x'$(printf "baz" | xxd -u -ps)' + THEN '$(printf "%s" "INBOX" | xxd -u -ps)' + WHEN mailbox = x'$(printf "bar" | xxd -u -ps)' + THEN '$(printf "%s" "foo" | xxd -u -ps)' + ELSE hex(mailbox) + END + FROM mailboxes + ORDER BY idx +EOF +diff -u --label="a/mailboxes.csv" --label="b/mailboxes.csv" \ + "$TMPDIR/mailboxes.csv" "$TMPDIR/mailboxes2.csv" \ + || error "Mailbox list differs" +step_done + +interimap +# recreated after renaming +grep -Fx "database: Created mailbox INBOX" <"$STDERR" + +check_mailbox_list +check_mailboxes_status "INBOX" "bar" "baz" + +# vim: set filetype=sh : diff --git a/tests/repair/local.conf b/tests/repair/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/repair/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/repair/remote.conf b/tests/repair/remote.conf new file mode 100644 index 0000000..1cbbc07 --- /dev/null +++ b/tests/repair/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ~ +} diff --git a/tests/05-repair/run b/tests/repair/t index 66f9ce9..6b205ea 100644 --- a/tests/05-repair/run +++ b/tests/repair/t @@ -9,7 +9,7 @@ for ((i = 0; i < 64; i++)); do sample_message | deliver -u "remote" -- -m "baz" done -interimap +interimap_init check_mailbox_list check_mailboxes_status "foo.bar" "baz" "INBOX" @@ -22,7 +22,7 @@ doveadm -u "remote" expunge mailbox "foo~bar" 4,5,7,10 doveadm -u "local" flags add "\\Answered" mailbox "foo.bar" 2,3,5:7,10 doveadm -u "remote" flags add "\\Seen" mailbox "foo~bar" 4,5,7 -# spoof HIGHESTMODSEQ value in the database, to make it look that we recorded the new changes already +# spoof HIGHESTMODSEQ value in the database to make it look that we recorded the new changes already spoof() { local k="$1" v m hex="$(printf "%s\\0%s" "foo" "bar" | xxd -ps)" shift @@ -46,7 +46,7 @@ doveadm -u "remote" mailbox status "all" "foo~bar" >"$TMPDIR/foo-bar.status.remo # verify that without --repair interimap does nothing due to the spoofed HIGHESTMODSEQ values -interimap "foo.bar" +interimap "foo.bar" || error sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump2.sql" <<-EOF .dump @@ -58,14 +58,14 @@ diff -u --label="a/foo_bar.local" --label="a/foo_bar.local" "$TMPDIR/foo-bar.s diff -u --label="a/foo_bar.remote" --label="a/foo_bar.remote" "$TMPDIR/foo-bar.status.remote" "$TMPDIR/foo-bar.status2.remote" -# deliver more messages and spoof UIDNEXT, on one side only +# deliver more messages and spoof UIDNEXT *on one side only* sample_message | deliver -u "local" -- -m "foo.bar" sample_message | deliver -u "remote" -- -m "foo~bar" spoof UIDNEXT "local" spoof HIGHESTMODSEQ "local" "remote" # now repair -interimap --repair "baz" "foo.bar" +interimap --repair "baz" "foo.bar" || error # 6 updates with \Answered (luid 4,8,11:13,16), 2 of which (luid 12,13) vanished from remote # 3 updates with \Seen (ruid 6,8,10), 1 of which (uid 10) vanished from remote @@ -82,26 +82,26 @@ xcgrep 5 -E '^local\(foo\.bar\): WARNING: UID [0-9]+ disappeared. Redownloading # 6-1 (luid 2 <-> ruid 10 is gone from both) xcgrep 3 -E '^remote\(foo~bar\): WARNING: UID [0-9]+ disappeared. Redownloading local UID [0-9]+\.$' <"$STDERR" -xgrep -E '^local\(baz\): Removed 24 UID\(s\) ' <"$STDERR" -xgrep -E '^remote\(baz\): Removed 5 UID\(s\) ' <"$STDERR" +grep -E '^local\(baz\): Removed 24 UID\(s\) ' <"$STDERR" || error +grep -E '^remote\(baz\): Removed 5 UID\(s\) ' <"$STDERR" || error -# pining UIDs here is not very robust... -xgrep -E '^local\(foo\.bar\): Updated flags \(\\Answered \\Seen\) for UID 16$' <"$STDERR" -xgrep -E '^local\(foo\.bar\): Updated flags \(\\Seen\) for UID 14$' <"$STDERR" -xgrep -E '^remote\(foo~bar\): Updated flags \(\\Answered \\Seen\) for UID 8$' <"$STDERR" -xgrep -E '^remote\(foo~bar\): Updated flags \(\\Answered\) for UID 3,12,16$' <"$STDERR" +# hardcoding UIDs here is not very robust... +grep -E '^local\(foo\.bar\): Updated flags \(\\Answered \\Seen\) for UID 16$' <"$STDERR" || error +grep -E '^local\(foo\.bar\): Updated flags \(\\Seen\) for UID 14$' <"$STDERR" || error +grep -E '^remote\(foo~bar\): Updated flags \(\\Answered \\Seen\) for UID 8$' <"$STDERR" || error +grep -E '^remote\(foo~bar\): Updated flags \(\\Answered\) for UID 3,12,16$' <"$STDERR" || error # luid 17 xcgrep 1 -E '^remote\(foo~bar\): WARNING: No match for modified local UID [0-9]+. Redownloading\.' <"$STDERR" -xgrep -E '^local\(foo\.bar\): Added 5 UID\(s\) ' <"$STDERR" -xgrep -E '^remote\(foo~bar\): Added 4 UID\(s\) ' <"$STDERR" -xgrep -E '^local\(foo\.bar\): Added 1 UID\(s\) ' <"$STDERR" # the new message +grep -E '^local\(foo\.bar\): Added 5 UID\(s\) ' <"$STDERR" || error +grep -E '^remote\(foo~bar\): Added 4 UID\(s\) ' <"$STDERR" || error +grep -E '^local\(foo\.bar\): Added 1 UID\(s\) ' <"$STDERR" || error # the new message check_mailbox_list check_mailboxes_status "baz" "foo.bar" -interimap +interimap || error check_mailboxes_status "baz" "foo.bar" "INBOX" # vim: set filetype=sh : diff --git a/tests/resume/local.conf b/tests/resume/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/resume/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/resume/remote.conf b/tests/resume/remote.conf new file mode 100644 index 0000000..1cbbc07 --- /dev/null +++ b/tests/resume/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ~ +} diff --git a/tests/04-resume/run b/tests/resume/t index 22d66bc..cb0208c 100644 --- a/tests/04-resume/run +++ b/tests/resume/t @@ -5,7 +5,7 @@ for ((i = 0; i < 8; i++)); do sample_message | deliver -u "local" -- -m "foo.bar" sample_message | deliver -u "local" -- -m "INBOX" done -interimap +interimap_init check_mailbox_list check_mailboxes_status "foo" "foo.bar" "baz" "INBOX" @@ -36,9 +36,9 @@ EOF doveadm -u "local" mailbox status "all" "foo" >"$TMPDIR/foo.local" doveadm -u "remote" mailbox status "all" "foo" >"$TMPDIR/foo.remote" -! interimap -xgrep -Fx "Resuming interrupted sync for foo" <"$STDERR" -xgrep -Fx "local(foo): ERROR: UIDVALIDITY changed! ($uidvalidity2 != $uidvalidity) Need to invalidate the UID cache." <"$STDERR" +! interimap || error +grep -Fx "Resuming interrupted sync for foo" <"$STDERR" +grep -Fx "local(foo): ERROR: UIDVALIDITY changed! ($uidvalidity2 != $uidvalidity) Need to invalidate the UID cache." <"$STDERR" sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/dump2.sql" <<-EOF .dump @@ -70,8 +70,8 @@ sample_message | deliver -u "remote" -- -m "foo~bar" sample_message | deliver -u "local" -- -m "baz" interimap "foo.bar" "InBoX" "baz" # ignore "foo" -xgrep -Fx "Resuming interrupted sync for foo.bar" <"$STDERR" -xgrep -Fx "Resuming interrupted sync for INBOX" <"$STDERR" +grep -Fx "Resuming interrupted sync for foo.bar" <"$STDERR" +grep -Fx "Resuming interrupted sync for INBOX" <"$STDERR" check_mailbox_list check_mailboxes_status "foo.bar" "INBOX" "baz" # ignore "foo" @@ -22,27 +22,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 <guilhem@fripost.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +#---------------------------------------------------------------------- + +set -ue +PATH=/usr/bin:/bin +export PATH + +BASEDIR="$(dirname -- "$0")" +RUN="$BASEDIR/run" + +failed=0 + +while IFS="" read -r x; do + if [[ "$x" =~ ^([[:blank:]]*)([^[:blank:]#]+)[[:blank:]]+(.*)$ ]]; then + indent="${BASH_REMATCH[1]}" + t="${BASH_REMATCH[2]}" + desc="${BASH_REMATCH[3]}" + + if [ "$t" = "." ]; then + printf "%s%s:\\n" "$indent" "$desc" + continue + elif [ "$t" = "..." ]; then + t="$desc" + desc="..." + fi + elif [[ "$x" =~ ^([[:blank:]]*)([^[:blank:]#]+)$ ]]; then + indent="${BASH_REMATCH[1]}" + t="${BASH_REMATCH[2]}" + unset desc + else + continue + fi + + if [ ! -d "$BASEDIR/$t" ]; then + printf "WARN: %s does doesn't exist, skipping\\n" "$t" >&2 + continue + fi + + INDENT="$indent" "$RUN" "$t" ${desc+"$desc"} || failed=$(( failed+1 )) +done <"$BASEDIR/list" + +if [ $failed -eq 0 ]; then + printf "All tests passed.\\n" + exit 0 +else + printf "%d test(s) failed.\\n" $failed + exit 1 +fi diff --git a/tests/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/07-sync-live-multi/local.conf b/tests/sync-live-multi/local.conf index baae39d..baae39d 100644 --- a/tests/07-sync-live-multi/local.conf +++ b/tests/sync-live-multi/local.conf diff --git a/tests/sync-live-multi/remote1.conf b/tests/sync-live-multi/remote1.conf new file mode 100644 index 0000000..2d08a24 --- /dev/null +++ b/tests/sync-live-multi/remote1.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ^ +} diff --git a/tests/sync-live-multi/remote2.conf b/tests/sync-live-multi/remote2.conf new file mode 100644 index 0000000..9657e89 --- /dev/null +++ b/tests/sync-live-multi/remote2.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = "\\" +} diff --git a/tests/sync-live-multi/remote3.conf b/tests/sync-live-multi/remote3.conf new file mode 100644 index 0000000..0b6aafd --- /dev/null +++ b/tests/sync-live-multi/remote3.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = "?" +} diff --git a/tests/sync-live-multi/remotes b/tests/sync-live-multi/remotes new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/tests/sync-live-multi/remotes @@ -0,0 +1 @@ +3 diff --git a/tests/07-sync-live-multi/run b/tests/sync-live-multi/t index 15a27fd..9b129ec 100644 --- a/tests/07-sync-live-multi/run +++ b/tests/sync-live-multi/t @@ -1,72 +1,59 @@ -# add references to each interimap instance -sed -ri 's#^\[local\]$#&\nlist-reference = foo/#' "$XDG_CONFIG_HOME/interimap/config" -sed -ri 's#^\[local\]$#&\nlist-reference = bar/#' "$XDG_CONFIG_HOME/interimap/config2" -sed -ri 's#^\[local\]$#&\nlist-reference = baz/#' "$XDG_CONFIG_HOME/interimap/config3" - -# create databases -interimap --config="config" -interimap --config="config2" -interimap --config="config3" - -# start long-lived interimap processes -interimap --config="config" --watch=1 & pid=$! -interimap --config="config2" --watch=1 & pid2=$! -interimap --config="config3" --watch=1 & pid3=$! - -abort() { - # kill interimap process and its children - pkill -P "$pid" -TERM || true - kill -TERM "$pid" || true - pkill -P "$pid2" -TERM || true - kill -TERM "$pid2" || true - pkill -P "$pid3" -TERM || true - kill -TERM "$pid3" || true - wait -} -trap abort EXIT INT TERM - +TIMEOUT=60 # mailbox list (as seen on local) and alphabet -declare -a mailboxes=( "INBOX" ) alphabet=() +declare -a MAILBOXES=( "INBOX" ) ALPHABET=() str="#+-0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" for ((i=0; i < ${#str}; i++)); do - alphabet[i]="${str:i:1}" + ALPHABET[i]="${str:i:1}" done -declare -a targets=( "local" "remote" "remote2" "remote3" ) +declare -a TARGETS=( "local" "remote1" "remote2" "remote3" ) + + +# create databases +interimap_init "remote1" +interimap_init "remote2" +interimap_init "remote3" + +# start long-lived interimap processes +declare -a PID=() +trap 'ptree_abort ${PID[@]}' EXIT INT TERM +interimap --config="config1" --watch=1 & PID+=( $! ) +interimap --config="config2" --watch=1 & PID+=( $! ) +interimap --config="config3" --watch=1 & PID+=( $! ) -timer=$(( $(date +%s) + 30 )) +timer=$(( $(date +%s) + TIMEOUT )) while [ $(date +%s) -le $timer ]; do # create new mailbox with 10% probability if [ $(shuf -n1 -i0-9) -eq 0 ]; then - u="$(shuf -n1 -e -- "${targets[@]}")" # choose target at random + u="$(shuf -n1 -e -- "${TARGETS[@]}")" # choose target at random case "$u" in local) ns="$(shuf -n1 -e "foo/" "bar/" "baz/")";; - remote) ns="foo/";; + remote1) ns="foo/";; remote2) ns="bar/";; remote3) ns="baz/";; - *) echo "Uh?" >&2; exit 1;; + *) error "Uh?";; esac m= d=$(shuf -n1 -i1-3) # random depth for (( i=0; i < d; i++)); do l=$(shuf -n1 -i1-16) - m="${m:+$m/}$(shuf -n "$l" -e -- "${alphabet[@]}" | tr -d '\n')" + m="${m:+$m/}$(shuf -n "$l" -e -- "${ALPHABET[@]}" | tr -d '\n')" done - mailboxes+=( "$ns$m" ) + MAILBOXES+=( "$ns$m" ) case "$u" in local) m="$ns$m";; - remote) m="${m//\//^}";; + remote1) m="${m//\//^}";; remote2) m="${m//\//\\}";; remote3) m="${m//\//\?}";; - *) echo "Uh?" >&2; exit 1;; + *) error "Uh?";; esac doveadm -u "$u" mailbox create -- "$m" fi # EXPUNGE some messages - u="$(shuf -n1 -e -- "${targets[@]}")" # choose target at random + u="$(shuf -n1 -e -- "${TARGETS[@]}")" # choose target at random n="$(shuf -n1 -i0-3)" while read guid uid; do doveadm -u "$u" expunge mailbox-guid "$guid" uid "$uid" @@ -74,7 +61,7 @@ while [ $(date +%s) -le $timer ]; do # mark some existing messages as read (toggle \Seen flag as unlike other # flags it's easier to query and check_mailboxes_status checks it) - u="$(shuf -n1 -e -- "${targets[@]}")" # choose target at random + u="$(shuf -n1 -e -- "${TARGETS[@]}")" # choose target at random n="$(shuf -n1 -i0-9)" while read guid uid; do a="$(shuf -n1 -e add remove replace)" @@ -83,14 +70,14 @@ while [ $(date +%s) -le $timer ]; do # select at random a mailbox where to deliver some messages u="$(shuf -n1 -e "local" "remote")" # choose target at random - m="$(shuf -n1 -e -- "${mailboxes[@]}")" + m="$(shuf -n1 -e -- "${MAILBOXES[@]}")" if [ "$u" = "remote" ]; then case "$m" in - foo/*) u="remote"; m="${m#foo/}"; m="${m//\//^}";; + foo/*) u="remote1"; m="${m#foo/}"; m="${m//\//^}";; bar/*) u="remote2"; m="${m#bar/}"; m="${m//\//\\}";; baz/*) u="remote3"; m="${m#baz/}"; m="${m//\//\?}";; - INBOX) u="$(shuf -n1 -e "remote" "remote2" "remote3")";; - *) echo "Uh? $m" >&2; exit 1;; + INBOX) u="$(shuf -n1 -e "remote1" "remote2" "remote3")";; + *) error "Uh? $m";; esac fi @@ -100,8 +87,10 @@ while [ $(date +%s) -le $timer ]; do sample_message | deliver -u "$u" -- -m "$m" done - # sleep a little bit - sleep "$(printf "0.%03d" "$(shuf -n1 -i1-999)")" + # sleep a little bit (sometimes beyond --watch timer, sometimes not) + s=$(shuf -n1 -i1-1500) + [ $s -ge 1000 ] && s="$(printf "1.%03d" $((s-1000)))" || s="$(printf "0.%03d" $s)" + sleep "$s" done # wait a little longer so interimap has time to run loop() again and @@ -109,13 +98,13 @@ done # started above sleep 2 -abort +ptree_abort ${PID[@]} trap - EXIT INT TERM # check that the mailbox lists match -diff -u --label="local/mailboxes" --label="remote/mailboxes" \ - <( doveadm -u "local" mailbox list | sed -n "s,^foo/,,p" | sort ) \ - <( doveadm -u "remote" mailbox list | tr '^' '/' | sort ) +diff -u --label="local/mailboxes" --label="remote1/mailboxes" \ + <( doveadm -u "local" mailbox list | sed -n "s,^foo/,,p" | sort ) \ + <( doveadm -u "remote1" mailbox list | tr '^' '/' | sort ) diff -u --label="local/mailboxes" --label="remote2/mailboxes" \ <( doveadm -u "local" mailbox list | sed -n "s,^bar/,,p" | sort ) \ <( doveadm -u "remote2" mailbox list | tr '\\' '/' | sort ) @@ -123,13 +112,13 @@ diff -u --label="local/mailboxes" --label="remote3/mailboxes" \ <( doveadm -u "local" mailbox list | sed -n "s,^baz/,,p" | sort ) \ <( doveadm -u "remote3" mailbox list | tr '?' '/' | sort ) -for m in "${mailboxes[@]}"; do +for m in "${MAILBOXES[@]}"; do case "$m" in - foo/*) u="remote"; mb="${m#foo/}"; mr="${mb//\//^}";; + foo/*) u="remote1"; mb="${m#foo/}"; mr="${mb//\//^}";; bar/*) u="remote2"; mb="${m#bar/}"; mr="${mb//\//\\}";; baz/*) u="remote3"; mb="${m#baz/}"; mr="${mb//\//\?}";; INBOX) continue;; - *) echo "Uh? $m" >&2; exit 1;; + *) error "Uh? $m";; esac blob="x'$(printf "%s" "$mb" | tr "/" "\\0" | xxd -c256 -ps)'" check_mailbox_status2 "$blob" "$m" "$u" "$mr" diff --git a/tests/sync-live/local.conf b/tests/sync-live/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/sync-live/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/sync-live/remote.conf b/tests/sync-live/remote.conf new file mode 100644 index 0000000..2d08a24 --- /dev/null +++ b/tests/sync-live/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ^ +} diff --git a/tests/07-sync-live/run b/tests/sync-live/t index 04d8247..19d1e08 100644 --- a/tests/07-sync-live/run +++ b/tests/sync-live/t @@ -1,25 +1,19 @@ -# create database -interimap - -# start a long-lived interimap process -interimap --watch=1 & pid=$! - -abort() { - # kill interimap process and its children - pkill -P "$pid" -TERM || true - kill -TERM "$pid" || true - wait -} -trap abort EXIT INT TERM +TIMEOUT=60 # mailbox list and alphabet (exclude &, / and ~, which dovecot treats specially) -declare -a mailboxes=( "INBOX" ) alphabet=() +declare -a MAILBOXES=( "INBOX" ) ALPHABET=() str="!\"#\$'()+,-0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\[\\\]_\`abcdefghijklmnopqrstuvwxyz{|}" for ((i=0; i < ${#str}; i++)); do - alphabet[i]="${str:i:1}" + ALPHABET[i]="${str:i:1}" done -timer=$(( $(date +%s) + 30 )) +interimap_init + +# start a long-lived interimap process +interimap --watch=1 & PID=$! +trap "ptree_abort $PID" EXIT INT TERM + +timer=$(( $(date +%s) + TIMEOUT )) while [ $(date +%s) -le $timer ]; do # create new mailbox with 10% probability if [ $(shuf -n1 -i0-9) -eq 0 ]; then @@ -27,9 +21,9 @@ while [ $(date +%s) -le $timer ]; do d=$(shuf -n1 -i1-3) # random depth for (( i=0; i < d; i++)); do l=$(shuf -n1 -i1-16) - m="${m:+$m.}$(shuf -n "$l" -e -- "${alphabet[@]}" | tr -d '\n')" + m="${m:+$m.}$(shuf -n "$l" -e -- "${ALPHABET[@]}" | tr -d '\n')" done - mailboxes+=( "$m" ) + MAILBOXES+=( "$m" ) u="$(shuf -n1 -e "local" "remote")" # choose target at random [ "$u" = "local" ] || m="${m//./^}" doveadm -u "$u" mailbox create -- "$m" @@ -53,7 +47,7 @@ while [ $(date +%s) -le $timer ]; do # select at random a mailbox where to deliver some messages u="$(shuf -n1 -e "local" "remote")" # choose target at random - m="$(shuf -n1 -e -- "${mailboxes[@]}")" + m="$(shuf -n1 -e -- "${MAILBOXES[@]}")" [ "$u" = "local" ] || m="${m//./^}" # deliver between 1 and 5 messages to the chosen mailbox @@ -62,8 +56,10 @@ while [ $(date +%s) -le $timer ]; do sample_message | deliver -u "$u" -- -m "$m" done - # sleep a little bit - sleep "$(printf "0.%03d" "$(shuf -n1 -i1-999)")" + # sleep a little bit (sometimes beyond --watch timer, sometimes not) + s=$(shuf -n1 -i1-1500) + [ $s -ge 1000 ] && s="$(printf "1.%03d" $((s-1000)))" || s="$(printf "0.%03d" $s)" + sleep "$s" done # wait a little longer so interimap has time to run loop() again and @@ -71,10 +67,10 @@ done # above sleep 2 -abort +ptree_abort $PID trap - EXIT INT TERM check_mailbox_list -check_mailboxes_status "${mailboxes[@]}" +check_mailboxes_status "${MAILBOXES[@]}" # vim: set filetype=sh : diff --git a/tests/sync-mailbox-list/local.conf b/tests/sync-mailbox-list/local.conf new file mode 100644 index 0000000..b56cc70 --- /dev/null +++ b/tests/sync-mailbox-list/local.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = . +} diff --git a/tests/sync-mailbox-list/remote.conf b/tests/sync-mailbox-list/remote.conf new file mode 100644 index 0000000..1cbbc07 --- /dev/null +++ b/tests/sync-mailbox-list/remote.conf @@ -0,0 +1,3 @@ +namespace inbox { + separator = ~ +} diff --git a/tests/sync-mailbox-list/t b/tests/sync-mailbox-list/t new file mode 100644 index 0000000..ea80fbf --- /dev/null +++ b/tests/sync-mailbox-list/t @@ -0,0 +1,93 @@ +# pre-create some mailboxes and susbscribe to some +# foo: present on both, subscribed to both +# bar: present on both, subscribed to local only +# baz: present on both, subscribed to remote only +# foo.bar: present on local only +# foo.baz: present on remote only +doveadm -u "local" mailbox create "foo" "bar" "baz" "foo.bar" "fo!o [b*a%r]" +doveadm -u "local" mailbox subscribe "foo" "bar" +doveadm -u "remote" mailbox create "foo" "bar" "baz" "foo~baz" "foo]bar" +doveadm -u "remote" mailbox subscribe "foo" "baz" + +populate() { + local i + for ((i = 0; i < 32; i++)); do + m="$(shuf -n1 -e -- "foo" "bar" "baz" "foo.bar" "fo!o [b*a%r]")" + sample_message | deliver -u "local" -- -m "$m" + + m="$(shuf -n1 -e -- "foo" "bar" "baz" "foo~baz" "foo]bar")" + sample_message | deliver -u "remote" -- -m "$m" + done +} +verify() { + check_mailbox_list || error + check_mailboxes_status "foo" "bar" "baz" "foo.bar" "foo.baz" "INBOX" "fo!o [b*a%r]" "foo]bar" +} +populate + +step_start "pre-subscribtions" +interimap_init +grep -Fx "local: Subscribe to baz" <"$STDERR" || error +grep -Fx "remote: Subscribe to bar" <"$STDERR" || error +grep -Fx "local: Created mailbox foo.baz" <"$STDERR" || error +grep -Fx "remote: Created mailbox foo~bar" <"$STDERR" || error +step_done + +# ensure the mailbox list is synchronized +step_start "mailbox list and content" +verify +check_mailbox_list -s +step_done + + +# delete a mailbox on one server and verify that synchronization fails as it's still in the database +step_start "aborts if present in database" +for u in "local" "remote"; do + [ "$u" = "local" ] && { m="foo.bar"; m2="$m"; } || { m="foo.baz"; m2="foo~baz"; } + + doveadm -u "$u" mailbox delete "$m2" + ! interimap || error + grep -Fx "database: ERROR: Mailbox $m exists. Run \`interimap --target=database --delete $m\` to delete." <"$STDERR" + + interimap --target="database" --delete "$m" || error + grep -Fx "database: Removed mailbox $m" <"$STDERR" || error + + interimap || error # create again + grep -Fx "database: Created mailbox $m" <"$STDERR" || error + grep -Fx "$u: Created mailbox $m2" <"$STDERR" || error +done +verify +check_mailbox_list -s +step_done + + + +# (un)subscribe from some mailboxes, including a non-existent one +step_start "new (un)subscribtions" +doveadm -u "local" mailbox unsubscribe "foo" +doveadm -u "remote" mailbox unsubscribe "bar" +doveadm -u "local" mailbox subscribe "foo.bar" "foo.nonexistent" "foo.baz" +doveadm -u "remote" mailbox subscribe "foo~bar" "bar~nonexistent" +populate + +interimap +grep -Fx "remote: Unsubscribe to foo" <"$STDERR" +grep -Fx "local: Unsubscribe to bar" <"$STDERR" +grep -Fx "remote: Subscribe to foo~baz" <"$STDERR" +verify +check_mailbox_list -s $(doveadm -u "local" mailbox list) # exclude "foo.nonexistent" and "bar~nonexistent" + +# check that "baz", "foo.bar" and "foo.baz" are the only subscribed mailboxes +sqlite3 "$XDG_DATA_HOME/interimap/remote.db" >"$TMPDIR/count" <<-EOF + SELECT COUNT(*) + FROM mailboxes + WHERE subscribed <> (mailbox IN ( + x'$(printf "%s" "baz" | xxd -ps)', + x'$(printf "%s\\0%s" "foo" "bar" | xxd -ps)', + x'$(printf "%s\\0%s" "foo" "baz" | xxd -ps)' + )) +EOF +[ $(< "$TMPDIR/count") -eq 0 ] || error +step_done + +# vim: set filetype=sh : |