#!/usr/bin/env bash
# The alternating-pairs protocol for measuring the description layer.
#
# S3 ran Askama / described / described / Askama by hand. Running it by hand is
# how a measurement ends up not comparable with the one before it: the mix, the
# VU count and the described set all have to be identical across the four runs,
# and only the middle two differ in what serves the screens.
#
# Two things this answers that S3's numbers do not:
#
#   ACCUMULATION. S3 measured ONE described screen in an otherwise-Askama mix,
#   and its verdict rests on database connection occupancy, which is exactly the
#   quantity that grows with the number of described screens. Six are converted.
#   Default here is all six.
#
#   THE MULTITHREADED REGIME. The two forum screens' work is an outbound HTTP
#   call, not a query, and the described version holds a BLOCKING-POOL thread
#   across it where Askama pays the same latency on a runtime worker. Sweep
#   MT_LATENCY to find the upstream latency at which that starts to cost
#   something. Sizing the pool is a config line either way, so the output worth
#   having is the threshold, not a pass/fail.
#
# Usage:
#   scripts/load-conversion-ab.sh                    # all six screens, 0ms upstream
#   MT_LATENCY=500 scripts/load-conversion-ab.sh     # slow Multithreaded
#   SCREENS=user_ssh_keys scripts/load-conversion-ab.sh   # reproduce S3's shape
#
# Read the report's `Rej` column before reading anything else. A rejected request
# is fast, so a route answering 403 or 404 wins a latency comparison it never ran.
#
# THE PROFILE IS RELEASE, and it is here rather than in shell history so a later
# reader knows which one produced the numbers. Render cost is the quantity being
# compared, and in debug it is dominated by unoptimized rendering, so a debug
# sweep measures rustc's -O0 output more than it measures the description layer.
# S3's section in the wiki does not record its profile, so treat any comparison
# against S3's figures as indicative rather than exact.

set -euo pipefail
cd "$(dirname "$0")/.."

# Half the virtual users on the dashboard is far above a real day. It is chosen
# so the described routes see enough concurrency to say anything at all; a
# production-shaped mix puts one user on them and one user reaches no contention.
: "${MIX:=anon:25,buyer:15,creator:10,dash:50}"
: "${VUS:=60}"
: "${DURATION:=60}"
: "${RAMP:=10}"
: "${SCREENS:=*}"
: "${MT_LATENCY:=0}"
: "${OUT:=target/load-ab}"

export TEST_DATABASE_URL="${TEST_DATABASE_URL:-postgres:///postgres}"
export LOAD_VUS="$VUS"
export LOAD_DURATION_SECS="$DURATION"
export LOAD_RAMP_SECS="$RAMP"
export LOAD_MIX="$MIX"
export LOAD_MT_LATENCY_MS="$MT_LATENCY"

mkdir -p "$OUT"

# Built once, outside the timed runs: a cold compile inside run 1 would show up
# as run 1 being slower than run 4, which is the shape the alternation exists to
# cancel out.
echo "Building the load binary (release)..."
cargo test --release --test load --no-run --quiet

run() {
    local label="$1"
    local screens="$2"
    local path="$OUT/$label.txt"
    echo
    echo "=== $label (QUASI_SCREENS=${screens:-<none>}) ==="
    QUASI_SCREENS="$screens" \
        cargo test --release --test load -- --ignored --nocapture 2>&1 | tee "$path" |
        sed -n '/LOAD TEST REPORT/,$p'
}

# Askama, described, described, Askama. The pairs are inner and the controls are
# outer so a drift in the box over the run (thermal, page cache, another process
# arriving) lands on both sides rather than on one.
run 1-askama ""
run 2-described "$SCREENS"
run 3-described "$SCREENS"
run 4-askama ""

echo
echo "Four reports under $OUT/. Compare 2+3 against 1+4, per endpoint label."
echo "The described screens report under 'HTMX described:*' in every run: same"
echo "address either way, so the rows line up and only what serves them changed."
