Files
bongo/contrib/testing/queue-lifecycle-check.sh
T
2026-07-23 11:50:36 +02:00

216 lines
5.8 KiB
Bash
Executable File

#!/bin/sh
#
# Exercise Queue administration, retry preservation, expiry, and DSN creation
# against a running local Bongo installation.
set -eu
user=${1:-stqqueue}
domain=${2:-bongo.test}
queue_tool=${BONGO_QUEUE_TOOL:-/usr/bin/bongo-queuetool}
store_tool=${BONGO_STORE_TOOL:-/usr/bin/bongo-storetool}
service=${BONGO_SERVICE:-bongo.service}
run_as=${BONGO_TEST_RUN_AS:-bongo}
as_root=${BONGO_TEST_AS_ROOT:-sudo -n}
if [ "$(id -un)" = "$run_as" ]; then
as_bongo=
else
as_bongo="sudo -n -u $run_as"
fi
work=$(mktemp -d "${TMPDIR:-/tmp}/bongo-stq05.XXXXXX")
chmod 0755 "$work"
managed_id=
retry_id=
expiry_id=
cleanup()
{
status=$?
for queue_id in "$managed_id" "$retry_id" "$expiry_id"; do
if [ -n "$queue_id" ]; then
$as_bongo "$queue_tool" delete "$queue_id" \
>/dev/null 2>&1 || true
fi
done
rm -rf "$work"
exit "$status"
}
trap cleanup EXIT HUP INT TERM
wait_queue()
{
attempts=30
while [ "$attempts" -gt 0 ]; do
if $as_bongo "$queue_tool" list >/dev/null 2>&1; then
return 0
fi
attempts=$((attempts - 1))
sleep 1
done
echo "STQ-05: Queue did not become ready" >&2
return 1
}
queue_contains()
{
$as_bongo "$queue_tool" list |
grep -F "$1 " >/dev/null
}
wait_message()
{
queue_id=$1
output=$2
attempts=30
while [ "$attempts" -gt 0 ]; do
if $as_bongo "$queue_tool" message "$queue_id" \
>"$output" 2>/dev/null; then
return 0
fi
attempts=$((attempts - 1))
sleep 1
done
echo "STQ-05: queue entry $queue_id did not become readable" >&2
return 1
}
printf '%s\r\n' \
"From: STQ-05 <stq05@$domain>" \
"To: $user@$domain" \
'Subject: STQ-05 queue lifecycle' \
'Date: Thu, 23 Jul 2026 12:34:56 +0200' \
'Message-ID: <stq05-lifecycle@bongo.test>' \
'' \
'Queue listing, hold, retry, expiry, bounce, and deletion.' \
>"$work/message.eml"
chmod 0644 "$work/message.eml"
# A normal committed entry must be listable, movable to hold, preserved across
# restart, releasable to an explicit target, and deletable.
managed_id=$($as_bongo "$queue_tool" hold-local "$work/message.eml" 9)
case "$managed_id" in
009-*) ;;
*)
echo "STQ-05: unexpected management fixture ID: $managed_id" >&2
exit 1
;;
esac
queue_contains "$managed_id"
held_id=$($as_bongo "$queue_tool" hold "$managed_id")
managed_id=$held_id
case "$managed_id" in
999-*) ;;
*)
echo "STQ-05: hold did not return a queue-999 ID: $managed_id" >&2
exit 1
;;
esac
queue_contains "$managed_id"
$as_root /usr/bin/systemctl restart "$service"
wait_queue
queue_contains "$managed_id"
released_id=$($as_bongo "$queue_tool" release "$managed_id" 9)
managed_id=$released_id
case "$managed_id" in
009-*) ;;
*)
echo "STQ-05: release did not return a queue-9 ID: $managed_id" >&2
exit 1
;;
esac
queue_contains "$managed_id"
$as_bongo "$queue_tool" delete "$managed_id"
if queue_contains "$managed_id"; then
echo "STQ-05: deleted entry remains in the listing" >&2
exit 1
fi
managed_id=
# A failed remote attempt must remain queued without changing the message.
retry_id=$($as_bongo "$queue_tool" enqueue-remote \
"$work/message.eml" "$user@$domain" nobody@retry.invalid 7)
case "$retry_id" in
007-*) ;;
*)
echo "STQ-05: unexpected retry fixture ID: $retry_id" >&2
exit 1
;;
esac
wait_message "$retry_id" "$work/retry-before.eml"
retry_before=$(sha256sum "$work/retry-before.eml" | awk '{ print $1 }')
$as_bongo "$queue_tool" flush
wait_message "$retry_id" "$work/retry-after.eml"
retry_after=$(sha256sum "$work/retry-after.eml" | awk '{ print $1 }')
if [ "$retry_before" != "$retry_after" ]; then
echo "STQ-05: retry changed the queued message" >&2
exit 1
fi
$as_bongo "$queue_tool" delete "$retry_id"
retry_id=
# Deterministic expiry starts in hold so the normal remote worker cannot race
# the diagnostic command. Exactly one DSN must appear in the isolated inbox.
$as_bongo "$store_tool" -u "$user" \
document-list /mail/INBOX >"$work/inbox-before"
expiry_id=$($as_bongo "$queue_tool" enqueue-remote \
"$work/message.eml" "$user@$domain" nobody@retry.invalid 999)
case "$expiry_id" in
999-*) ;;
*)
echo "STQ-05: unexpected expiry fixture ID: $expiry_id" >&2
exit 1
;;
esac
$as_bongo "$queue_tool" expire "$expiry_id" >/dev/null
expiry_id=
attempts=30
while [ "$attempts" -gt 0 ]; do
$as_bongo "$store_tool" -u "$user" \
document-list /mail/INBOX >"$work/inbox-after"
awk '{ print $1 }' "$work/inbox-before" | sort -u \
>"$work/inbox-before.ids"
awk '{ print $1 }' "$work/inbox-after" | sort -u \
>"$work/inbox-after.ids"
comm -13 "$work/inbox-before.ids" "$work/inbox-after.ids" \
>"$work/new.ids"
if [ "$(wc -l <"$work/new.ids")" -eq 1 ]; then
break
fi
attempts=$((attempts - 1))
sleep 1
done
if [ "$(wc -l <"$work/new.ids")" -ne 1 ]; then
echo "STQ-05: expiry did not create exactly one DSN" >&2
diff -u "$work/inbox-before" "$work/inbox-after" >&2 || true
exit 1
fi
document=$(sed -n '1p' "$work/new.ids")
document_path=$(awk -v id="$document" '$1 == id { print $3 }' \
"$work/inbox-after")
$as_bongo "$store_tool" -u "$user" \
document-get "$document_path" - >"$work/dsn.eml"
for expected in \
'Subject: Returned mail: Delivery time exceeded' \
'Original-recipient: rfc822;nobody@retry.invalid' \
'Final-recipient: rfc822;nobody@retry.invalid' \
'Action: failed' \
'Status: 5.4.7'
do
if ! grep -F "$expected" "$work/dsn.eml" >/dev/null; then
echo "STQ-05: generated DSN lacks '$expected'" >&2
exit 1
fi
done
printf 'STQ-05 PASS management=hold/restart/release/delete retry-sha256=%s dsn=%s status=5.4.7\n' \
"$retry_after" "$document"