#!/usr/bin/env bash # Tests for pull-domains.sh against a local "agent" directory (RSYNC_SRC # override) instead of ssh. Needs tinycdb's `cdb` and rsync in PATH. # Run with `make test-contrib`. set -u HERE=$(cd "$(dirname "$0")" && pwd) SCRIPT=$HERE/pull-domains.sh TMP=$(mktemp -d) trap 'rm -rf "$TMP"' EXIT export RSYNC_SRC=$TMP/agent/rspamd_domains_db export MAPS_DIR=$TMP/maps export DOMAINS_DIR=$TMP/db export DOMAINS_CDB=$DOMAINS_DIR/rspamd_domains_db export LOG_FILE=$TMP/pull.log export LOCK_FILE=$TMP/.pull-lock export RELOAD_CMD="touch $TMP/reloaded" mkdir -p "$TMP/agent" "$DOMAINS_DIR" fails=0 pass() { echo "ok - $1"; } fail() { echo "FAIL - $1"; fails=$((fails + 1)); } check() { if eval "$2"; then pass "$1"; else fail "$1"; fi; } # make_cdb FILE KEY VALUE: build a one-record CDB the way the agent does (cdb -c). make_cdb() { printf '+%d,%d:%s->%s\n\n' "${#2}" "${#3}" "$2" "$3" | cdb -c "$1" } inode() { stat -f %i "$1" 2>/dev/null || stat -c %i "$1"; } # --- 1. first install ------------------------------------------------------- make_cdb "$RSYNC_SRC" example.com "1049|A/i=200,A/o=20" rm -f "$TMP/reloaded" "$SCRIPT" >/dev/null 2>&1; rc=$? check "first run exits 0" "[ $rc -eq 0 ]" check "first run installs the CDB" "[ -f '$DOMAINS_CDB' ] && cmp -s '$RSYNC_SRC' '$DOMAINS_CDB'" check "first run keeps the .orig baseline" "cmp -s '$RSYNC_SRC' '$DOMAINS_CDB.orig'" check "first run reloads the daemon" "[ -f '$TMP/reloaded' ]" check "no temp file left behind" "! ls '$DOMAINS_DIR'/.rspamd_domains_db.* >/dev/null 2>&1" check "lock released" "[ ! -f '$LOCK_FILE' ]" check "log written" "grep -q 'rspamd_domains_db' '$LOG_FILE'" # --- 2. unchanged source ---------------------------------------------------- before=$(inode "$DOMAINS_CDB") rm -f "$TMP/reloaded" "$SCRIPT" >/dev/null 2>&1; rc=$? check "unchanged run exits 0" "[ $rc -eq 0 ]" check "unchanged run does not replace the file (same inode)" "[ '$(inode "$DOMAINS_CDB")' = '$before' ]" check "unchanged run does not reload" "[ ! -f '$TMP/reloaded' ]" check "unchanged run logs the skip" "grep -q 'unchanged' '$LOG_FILE'" # --- 3. changed source ------------------------------------------------------- make_cdb "$RSYNC_SRC" example.com "1049|A/i=500,A/o=50" rm -f "$TMP/reloaded" "$SCRIPT" >/dev/null 2>&1; rc=$? check "changed run exits 0" "[ $rc -eq 0 ]" check "changed run installs atomically (new inode)" "[ '$(inode "$DOMAINS_CDB")' != '$before' ]" check "changed run installs the new content" "cmp -s '$RSYNC_SRC' '$DOMAINS_CDB'" check "changed run updates .orig" "cmp -s '$RSYNC_SRC' '$DOMAINS_CDB.orig'" check "changed run reloads the daemon" "[ -f '$TMP/reloaded' ]" check "changed run logs the install" "grep -q 'installed' '$LOG_FILE'" # --- 4. corrupt source ------------------------------------------------------- good_inode=$(inode "$DOMAINS_CDB") cp "$DOMAINS_CDB" "$TMP/good.copy" printf 'garbage' > "$RSYNC_SRC" rm -f "$TMP/reloaded" "$SCRIPT" >/dev/null 2>&1; rc=$? check "corrupt source exits non-zero" "[ $rc -ne 0 ]" check "corrupt source leaves the installed file untouched" "[ '$(inode "$DOMAINS_CDB")' = '$good_inode' ] && cmp -s '$DOMAINS_CDB' '$TMP/good.copy'" check "corrupt source does not touch .orig" "cmp -s '$DOMAINS_CDB.orig' '$TMP/good.copy'" check "corrupt source does not reload" "[ ! -f '$TMP/reloaded' ]" check "corrupt source leaves no temp file" "! ls '$DOMAINS_DIR'/.rspamd_domains_db.* >/dev/null 2>&1" check "corrupt source releases the lock" "[ ! -f '$LOCK_FILE' ]" check "corrupt source is logged" "grep -q 'not a valid CDB' '$LOG_FILE'" # An empty CDB (zero records) is just as useless: refused too. printf '\n' | cdb -c "$RSYNC_SRC" "$SCRIPT" >/dev/null 2>&1; rc=$? check "empty CDB is refused" "[ $rc -ne 0 ] && cmp -s '$DOMAINS_CDB' '$TMP/good.copy'" # --- 5. lock file ------------------------------------------------------------- make_cdb "$RSYNC_SRC" example.com "1049|A/i=1,A/o=1" touch "$LOCK_FILE" "$SCRIPT" >/dev/null 2>&1; rc=$? check "fresh lock skips the run (exit 0)" "[ $rc -eq 0 ]" check "fresh lock leaves the file alone" "cmp -s '$DOMAINS_CDB' '$TMP/good.copy'" check "fresh lock is logged" "grep -q 'still running' '$LOG_FILE'" touch -t 200001010000 "$LOCK_FILE" # stale "$SCRIPT" >/dev/null 2>&1; rc=$? check "stale lock is ignored" "[ $rc -eq 0 ] && cmp -s '$RSYNC_SRC' '$DOMAINS_CDB'" # --- 6. the pull itself fails ------------------------------------------------ rm -f "$RSYNC_SRC" "$SCRIPT" >/dev/null 2>&1; rc=$? check "missing source exits non-zero and keeps the installed file" "[ $rc -ne 0 ] && [ -f '$DOMAINS_CDB' ]" check "failed pull releases the lock" "[ ! -f '$LOCK_FILE' ]" echo if [ $fails -eq 0 ]; then echo "all contrib tests passed"; else echo "$fails contrib test(s) FAILED"; exit 1; fi