aboutsummaryrefslogtreecommitdiffstats
path: root/tests/run
diff options
context:
space:
mode:
Diffstat (limited to 'tests/run')
-rwxr-xr-xtests/run288
1 files changed, 204 insertions, 84 deletions
diff --git a/tests/run b/tests/run
index ee11757..30d20f9 100755
--- a/tests/run
+++ b/tests/run
@@ -22,27 +22,39 @@ set -ue
PATH=/usr/bin:/bin
export PATH
-if [ $# -ne 1 ]; then
- printf "Usage: %s TESTNAME\\n" "$0" >&2
+if [ $# -eq 0 ] || [ $# -gt 2 ]; then
+ printf "Usage: %s TESTFILE [TESTNAME]\\n" "$0" >&2
exit 1
fi
-TEST="${1%/}"
-TEST="${TEST##*/}"
-NAME="${TEST#[0-9]*-}"
-TESTDIR="$(dirname -- "$0")/$TEST"
+BASEDIR="$(dirname -- "$0")"
+TESTDIR="$BASEDIR/$1"
+TESTNAME="${2-$1}"
if [ ! -d "$TESTDIR" ]; then
printf "ERROR: Not a directory: %s\\n" "$TESTDIR" >&2
exit 1
fi
-ROOTDIR="$(mktemp --tmpdir="${TMPDIR:-/dev/shm}" --directory "$NAME.XXXXXXXXXX")"
-trap 'rm -rf -- "$ROOTDIR"' EXIT INT TERM
+ROOTDIR="$(mktemp --tmpdir="${TMPDIR:-/dev/shm}" --directory "$1.XXXXXXXXXX")"
+declare -a DOVECOT_SERVER=()
+trap cleanup EXIT INT TERM
+cleanup() {
+ local pid c
+ for c in "${DOVECOT_SERVER[@]}"; do
+ if [ ! -f "$c" ] || ! env -i PATH="/usr/bin:/bin" doveadm -c "$c" stop; then
+ pid="$(< "${c%/*}/run/master.pid")"
+ kill -TERM "$pid" || printf "kill(1) exited with status %d\\n" "$?" >&2
+ fi
+ done
+ rm -rf -- "$ROOTDIR"
+}
-STDOUT="$ROOTDIR/stdout"
-STDERR="$ROOTDIR/stderr"
+_STDOUT="$ROOTDIR/stdout"
+_STDERR="$ROOTDIR/stderr"
TMPDIR="$ROOTDIR/tmp"
+STDERR="$(mktemp --tmpdir="$ROOTDIR" "stderr.XXXXXXXXXX")"
mkdir -- "$TMPDIR" "$ROOTDIR/home"
+declare -a REMOTES=()
# Set environment for the given user
environ_set() {
@@ -60,65 +72,151 @@ environ_set() {
# Prepare the test harness
prepare() {
declare -a ENVIRON=()
- local src cfg target u home
+ local src cfg target u home n proto
+ if [ -f "$TESTDIR/remotes" ] || [ -L "$TESTDIR/remotes" ]; then
+ for cfg in $(seq 1 "$(< "$TESTDIR/remotes")"); do
+ REMOTES+=( "remote$cfg" )
+ done
+ else
+ REMOTES+=( "remote" )
+ fi
# copy dovecot config
- for src in "$TESTDIR/local.conf" "$TESTDIR"/remote*.conf; do
- [ -r "$src" ] || continue
- u="${src#"$TESTDIR/"}"
- u="${u%.conf}"
- home="$ROOTDIR/home/$u"
+ for u in "local" "${REMOTES[@]}"; do
+ home="$ROOTDIR/$u/home"
export "HOME_$u"="$home"
- mkdir -pm0755 -- "$home/.local/bin"
- mkdir -pm0700 -- "$home/.config/dovecot"
- cat >"$home/.config/dovecot/config" <<-EOF
- log_path = /dev/null
- mail_home = $ROOTDIR/home/%u
+ environ_set "$u"
+
+ mkdir -pm0700 -- "$home/.dovecot"
+ cat >"$home/.dovecot/config" <<-EOF
+ log_path = $HOME_local/mail.log
+ mail_home = $home
+ mail_location = dbox:~/inbox:LAYOUT=index
mailbox_list_index = yes
ssl = no
+ listen = 127.0.0.1, ::1
+ namespace inbox {
+ inbox = yes
+ }
EOF
- cat >>"$home/.config/dovecot/config" <"$src"
- environ_set "$u"
+ if [ -f "$TESTDIR/$u.conf" ] || [ -L "$TESTDIR/$u.conf" ]; then
+ cat >>"$home/.dovecot/config" <"$TESTDIR/$u.conf"
+ fi
+ cp -aT -- "$BASEDIR/snippets/dovecot" "$home/.dovecot/conf.d"
+
+ proto="$(env -i "${ENVIRON[@]}" doveconf -c "$home/.dovecot/config" -h protocols)"
+ if [ -n "$proto" ]; then
+ cat >>"$home/.dovecot/config" <<-EOF
+ # https://wiki.dovecot.org/HowTo/Rootless
+ base_dir = $home/.dovecot/run
+ default_internal_user = $(id -un)
+ default_internal_group = $(id -gn)
+ default_login_user = $(id -un)
+
+ service anvil {
+ chroot =
+ }
+ service imap-login {
+ chroot =
+ }
+ service stats {
+ chroot =
+ }
+
+ passdb {
+ args = scheme=PLAIN username_format=%u $home/.dovecot/users
+ driver = passwd-file
+ }
+ userdb {
+ args = username_format=%u $home/.dovecot/users
+ driver = passwd-file
+ }
+ EOF
+
+ env -i PATH="/usr/bin:/bin" /usr/sbin/dovecot -c "$home/.dovecot/config"
+ DOVECOT_SERVER+=( "$home/.dovecot/config" )
+ printf "%s:%s:::::\\n" "$u" "$(xxd -l16 -p </dev/urandom)" >"$home/.dovecot/users"
+ fi
+
+ mkdir -pm0755 -- "$home/.local/bin"
cat >"$home/.local/bin/doveadm" <<-EOF
#!/bin/sh
exec env -i ${ENVIRON[@]@Q} \\
- doveadm -c ${home@Q}/.config/dovecot/config "\$@"
+ doveadm -c ${home@Q}/.dovecot/config "\$@"
EOF
chmod +x -- "$home/.local/bin/doveadm"
done
- # copy interimap config
- mkdir -pm0700 -- "$HOME_local/.local/share/interimap"
- mkdir -pm0700 -- "$HOME_local/.config/interimap"
- for cfg in "$TESTDIR"/remote*.conf; do
- cfg="${cfg#"$TESTDIR/remote"}"
- cfg="${cfg%.conf}"
- u="remote$cfg"
+ # copy interimap and pullimap configuration
+ mkdir -pm0700 -- "$HOME_local/.local/share/interimap" "$HOME_local/.local/share/pullimap"
+ mkdir -pm0700 -- "$HOME_local/.config/interimap" "$HOME_local/.config/pullimap"
+ echo "deliver-rcpt = local" >>"$HOME_local/.config/pullimap/config"
+ for u in "${REMOTES[@]}"; do
+ n="${u#remote}"
eval home="\$HOME_$u"
- if [ -f "$TESTDIR/interimap.conf" ]; then
- cat <"$TESTDIR/interimap.conf" >>"$HOME_local/.config/interimap/config$cfg"
- fi
- cat >>"$HOME_local/.config/interimap/config$cfg" <<-EOF
+
+ cat >>"$HOME_local/.config/interimap/config$n" <<-EOF
database = $u.db
-
+ #logfile = $HOME_local/interimap$n.log
+ EOF
+ if [ -f "$TESTDIR/interimap$n.conf" ] || [ -L "$TESTDIR/interimap$n.conf" ]; then
+ cat <"$TESTDIR/interimap$n.conf" >>"$HOME_local/.config/interimap/config$n"
+ fi
+ if [ -f "$TESTDIR/pullimap.conf" ] || [ -L "$TESTDIR/pullimap.conf" ]; then
+ cat <"$TESTDIR/pullimap.conf" >>"$HOME_local/.config/pullimap/config"
+ fi
+
+ cat >>"$HOME_local/.config/interimap/config$n" <<-EOF
+
[local]
type = tunnel
command = exec ${HOME_local@Q}/.local/bin/doveadm exec imap
null-stderr = NO
-
- [remote]
- type = tunnel
- command = exec ${home@Q}/.local/bin/doveadm exec imap
- null-stderr = NO
EOF
+ if [ -f "$TESTDIR/interimap$n.local" ] || [ -L "$TESTDIR/interimap$n.local" ]; then
+ cat <"$TESTDIR/interimap$n.local" >>"$HOME_local/.config/interimap/config$n"
+ fi
+
+ if [ -s "$home/.dovecot/users" ]; then
+ cat <<-EOF
+ username = $u
+ password = $(awk -F: -vu="$u" '$1 == u {print $2}' <"$home/.dovecot/users")
+ EOF
+ else
+ cat <<-EOF
+ type = tunnel
+ command = exec ${home@Q}/.local/bin/doveadm exec imap
+ null-stderr = NO
+ EOF
+ fi >"$HOME_local/.$u.conf"
+ if [ -f "$TESTDIR/interimap$n.remote" ] || [ -L "$TESTDIR/interimap$n.remote" ]; then
+ cat <"$TESTDIR/interimap$n.remote" >>"$HOME_local/.$u.conf"
+ fi
+
+ { printf "\\n[remote]\\n"; cat <"$HOME_local/.$u.conf"; } >>"$HOME_local/.config/interimap/config$n"
+ { printf "\\n[%s]\\n" "$u"; cat <"$HOME_local/.$u.conf"; } >>"$HOME_local/.config/pullimap/config"
done
}
prepare
# Wrappers for interimap(1) and doveadm(1)
-interimap() {
- declare -a ENVIRON=()
+interimap() { _interimap_cmd "interimap" "$@"; }
+pullimap() { _interimap_cmd "pullimap" "$@"; }
+_interimap_cmd() {
+ declare -a ENVIRON=() r=0
+ local script="$1"
+ shift
environ_set "local"
- env -i "${ENVIRON[@]}" perl -I./lib -T ./interimap "$@"
+ env -i "${ENVIRON[@]}" perl -I./lib -T "./$script" "$@" 2> >(tee "$STDERR" >&2)
+}
+interimap_init() {
+ local u="${1-remote}"
+ local db="$XDG_DATA_HOME/interimap/$u.db"
+ local cfg="config${u#remote}"
+
+ test \! -e "$db" || error "Database already exists" 1
+ interimap --config "$cfg" || error "Couldn't initialize interimap" 1
+ test -f "$db" || error "Database is still missing" 1
+ grep -Fx "Creating new schema in database file $db" <"$STDERR" || error "DB wasn't created" 1
}
doveadm() {
if [ $# -le 2 ] || [ "$1" != "-u" ]; then
@@ -137,8 +235,10 @@ sqlite3() {
# Sample (random) message
sample_message() {
local date="$(date +"%s.%N")"
+ # also try non-conventional addresses for pullimap
+ local sender="$(shuf -n1 -e "sender" "first.last" "foo-bar" \"\" "\"x\\\" #&\\\\y\"" )"
cat <<-EOF
- From: <sender@example.net>
+ From: <$sender@example.net>
To: <recipient@example.net>
Date: $(date -R -d@"$date")
Message-ID: <$date@example.net>
@@ -150,7 +250,7 @@ sample_message() {
# Wrapper for dovecot-lda(1)
deliver() {
- local -a argv
+ declare -a argv
while [ $# -gt 0 ] && [ "$1" != "--" ]; do
argv+=( "$1" )
shift
@@ -167,36 +267,40 @@ dump_test_result() {
local above="<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
local src u home
declare -a ENVIRON=()
- for src in "$TESTDIR/local.conf" "$TESTDIR"/remote*.conf; do
- u="${src#"$TESTDIR/"}"
- u="${u%.conf}"
+ for u in "local" "${REMOTES[@]}"; do
environ_set "$u"
eval home="\$HOME_$u"
printf "%s dovecot configuration:\\n%s\\n" "$u" "$below"
- env -i "${ENVIRON[@]}" doveconf -c "$home/.config/dovecot/config" -n
+ env -i "${ENVIRON[@]}" doveconf -c "$home/.dovecot/config" -n
+ printf "%s\\n\\n" "$above"
+ done
+
+ for u in "${REMOTES[@]}"; do
+ printf "interimap configuration (local <-> $u):\\n%s\\n" "$below"
+ cat <"$HOME_local/.config/interimap/config${u#remote}"
printf "%s\\n\\n" "$above"
done
- printf "(local) interimap configuration:\\n%s\\n" "$below"
- cat <"$HOME_local/.config/interimap/config"
+ printf "mail.log:\\n%s\\n" "$below"
+ cat -- "$HOME_local/mail.log" 2>/dev/null || true
printf "%s\\n\\n" "$above"
- printf "standard output was:\\n%s\\n" "$below"
- cat <"$STDOUT"
+ printf "standard output:\\n%s\\n" "$below"
+ cat <"$_STDOUT"
printf "%s\\n\\n" "$above"
- printf "standard error was:\\n%s\\n" "$below"
- cat <"$STDERR"
+ printf "standard error:\\n%s\\n" "$below"
+ cat <"$_STDERR"
printf "%s\\n\\n" "$above"
}
# Check mailbox consistency between the local/remote server and interimap's database
check_mailbox_status() {
local mailbox="$1" lns="inbox" lsep lprefix rns="inbox" rsep rprefix
- lsep="$(doveconf -c "$HOME_local/.config/dovecot/config" -h "namespace/$lns/separator")"
- lprefix="$(doveconf -c "$HOME_local/.config/dovecot/config" -h "namespace/$lns/prefix")"
- rsep="$(doveconf -c "$HOME_remote/.config/dovecot/config" -h "namespace/$lns/separator")"
- rprefix="$(doveconf -c "$HOME_remote/.config/dovecot/config" -h "namespace/$lns/prefix")"
+ lsep="$(doveconf -c "$HOME_local/.dovecot/config" -h "namespace/$lns/separator")"
+ lprefix="$(doveconf -c "$HOME_local/.dovecot/config" -h "namespace/$lns/prefix")"
+ rsep="$(doveconf -c "$HOME_remote/.dovecot/config" -h "namespace/$lns/separator")"
+ rprefix="$(doveconf -c "$HOME_remote/.dovecot/config" -h "namespace/$lns/prefix")"
local blob="x'$(printf "%s" "$mailbox" | tr "$lsep" "\\0" | xxd -c256 -ps)'"
local rmailbox="$(printf "%s" "$mailbox" | tr "$lsep" "$rsep")"
@@ -225,7 +329,7 @@ check_mailbox_status2() {
WHERE mailbox = $blob
EOF
)
- check_mailbox_status_values "local" "$lmailbox" $lUIDVALIDITY $lUIDNEXT $lHIGHESTMODSEQ $MESSAGES
+ check_mailbox_status_values "local" "$lmailbox" $lUIDVALIDITY $lUIDNEXT $lHIGHESTMODSEQ $MESSAGES
check_mailbox_status_values "$u" "$rmailbox" $rUIDVALIDITY $rUIDNEXT $rHIGHESTMODSEQ $MESSAGES
local a b
@@ -268,10 +372,10 @@ check_mailboxes_status() {
# Check mailbox list constency between the local and remote servers
check_mailbox_list() {
local m i lns="inbox" lsep lprefix rns="inbox" rsep rprefix sub=
- lsep="$(doveconf -c "$HOME_local/.config/dovecot/config" -h "namespace/$lns/separator")"
- lprefix="$(doveconf -c "$HOME_local/.config/dovecot/config" -h "namespace/$lns/prefix")"
- rsep="$(doveconf -c "$HOME_remote/.config/dovecot/config" -h "namespace/$lns/separator")"
- rprefix="$(doveconf -c "$HOME_remote/.config/dovecot/config" -h "namespace/$lns/prefix")"
+ lsep="$(doveconf -c "$HOME_local/.dovecot/config" -h "namespace/$lns/separator")"
+ lprefix="$(doveconf -c "$HOME_local/.dovecot/config" -h "namespace/$lns/prefix")"
+ rsep="$(doveconf -c "$HOME_remote/.dovecot/config" -h "namespace/$lns/separator")"
+ rprefix="$(doveconf -c "$HOME_remote/.dovecot/config" -h "namespace/$lns/prefix")"
if [ $# -gt 0 ] && [ "$1" = "-s" ]; then
sub="-s"
shift
@@ -304,38 +408,54 @@ check_mailbox_list() {
<( printf "%s" "${lmailboxes[*]}" | sort ) <( printf "%s" "${rmailboxes[*]}" | sort )
}
-# Wrappers for grep(1) and `grep -C`
-xgrep() {
- if ! grep -q "$@"; then
- printf "\`grep %s\` failed on line %d\\n" "${*@Q}" ${BASH_LINENO[0]} >&2
- exit 1
- fi
-}
+# Wrapper for `grep -c`
xcgrep() {
local m="$1" n
shift
if ! n="$(grep -c "$@")" || [ $m -ne $n ]; then
- printf "\`grep -c %s\` failed on line %d: %d != %d\\n" "${*@Q}" ${BASH_LINENO[0]} "$m" "$n" >&2
- exit 1
+ error "\`grep -c ${*@Q}\` failed ($m != $n)" 1
fi
}
+error() {
+ local err="${1+": $1"}" i=${2-0}
+ printf "ERROR$err on file %s line %d\\n" "${BASH_SOURCE[i+1]}" ${BASH_LINENO[i]} >&2
+ exit 1
+}
+ptree_abort() {
+ local pid
+ for pid in "$@"; do
+ # kill a process and its children
+ pkill -TERM -P "$pid" || printf "pkill(1) exited with status %d\\n" "$?" >&2
+ kill -TERM "$pid" || printf "kill(1) exited with status %d\\n" "$?" >&2
+ done
+ wait
+}
+step_start() { printf "%s%s..." "${INDENT-}" "$1" >&3; }
+step_done() { passed >&3; }
+failed() {
+ [ -t 1 ] && printf " \\x1B[1;31mFAILED\\x1B[0m\\n" || echo " FAILED"
+}
+passed() {
+ [ -t 1 ] && printf " \\x1B[1;32mPASSED\\x1B[0m\\n" || echo " PASSED"
+}
# Run test in a sub-shell
declare -a ENVIRON=()
environ_set "local"
-export TMPDIR TESTDIR STDOUT STDERR "${ENVIRON[@]}"
-export -f environ_set doveadm interimap sqlite3 sample_message deliver
+export TMPDIR TESTDIR STDERR "${ENVIRON[@]}"
+export -f environ_set doveadm interimap interimap_init pullimap _interimap_cmd
+export -f sqlite3 sample_message deliver ptree_abort step_start step_done passed
export -f check_mailbox_status check_mailbox_status_values check_mailbox_status2
-export -f check_mailboxes_status check_mailbox_list xgrep xcgrep
-printf "%s..." "$TEST"
-if ! bash -ue "$TESTDIR/run" >"$STDOUT" 2>"$STDERR"; then
- echo " FAILED"
- dump_test_result
+export -f check_mailboxes_status check_mailbox_list xcgrep error
+[ "$TESTNAME" = "..." ] || printf "%s%s..." "${INDENT-}" "$TESTNAME"
+if ! bash -ue "$TESTDIR/t" 3>&1 >"$_STDOUT" 2>"$_STDERR"; then
+ failed
+ [ "${QUIET-n}" = "y" ] || dump_test_result
exit 1
else
- echo " OK"
- if grep -Paq "\\x00" -- "$STDOUT" "$STDERR"; then
- printf "\\tWarn: binary output (outstanding \\0)!\\n"
+ [ "$TESTNAME" = "..." ] || passed
+ if grep -Paq "\\x00" -- "$_STDOUT" "$_STDERR"; then
+ printf "\\tWARN: binary output (outstanding \\0)!\\n"
fi
exit 0
fi