#!/usr/bin/env bash
# Replays recorded bid requests against a running bidder and checks each
# answer. The folder a fixture sits in says what the bidder must do:
#   fixtures/bid/        valid request, expect 200 and a clean BidResponse
#   fixtures/no-bid/     valid request, expect 204
#   fixtures/invalid/    request that fails validation, expect 200 with nbr 2
#   fixtures/malformed/  body that is not JSON, expect 400
# Usage: BIDDER_URL=http://localhost:8080/bid bash scripts/test-bidder.sh [fixtures]
set -euo pipefail

FIXTURES="${1:-fixtures}"
BIDDER_URL="${BIDDER_URL:-http://localhost:8080/bid}"
SPEC="${SPEC:-2.6-202606}"
OUT="${OUT:-out}"
mkdir -p "$OUT"
shopt -s nullglob
failures=0

pass() { echo "ok    $1"; }
fail() { echo "FAIL  $1: $2"; failures=$((failures + 1)); }

# rtblint exits 0 when valid, 1 on spec errors, 2 when it cannot run.
# Exit 2 stops the script: a broken check must not look like a pass.
lint() {
  local status=0
  rtblint validate --version "$SPEC" --format json "$@" >"$OUT/report.json" || status=$?
  if [ "$status" -eq 2 ]; then
    echo "rtblint could not run: rtblint validate $*" >&2
    exit 2
  fi
  return "$status"
}

# Posts a fixture, writes the body to $2, prints the HTTP status.
post() {
  curl -s -o "$2" -w '%{http_code}' -X POST "$BIDDER_URL" \
    -H 'content-type: application/json' -H 'x-openrtb-version: 2.6' \
    --data-binary "@$1"
}

for req in "$FIXTURES"/bid/*.json; do
  name="bid/$(basename "$req")"
  resp="$OUT/$(basename "$req" .json).response.json"
  lint "$req" || { fail "$name" "fixture is not a valid request"; continue; }
  status="$(post "$req" "$resp")"
  [ "$status" = 200 ] || { fail "$name" "expected 200, got $status"; continue; }
  if ! lint --type response --request "$req" "$resp"; then
    fail "$name" "response fails validation against its request"
    jq -c '.issues[]' "$OUT/report.json"
    continue
  fi
  # Your own responses should be clean, so warnings fail the build too.
  if ! jq -e '.issues == []' "$OUT/report.json" >/dev/null; then
    fail "$name" "response has warnings"
    jq -c '.issues[]' "$OUT/report.json"
    continue
  fi
  pass "$name"
done

for req in "$FIXTURES"/no-bid/*.json; do
  name="no-bid/$(basename "$req")"
  lint "$req" || { fail "$name" "fixture is not a valid request"; continue; }
  status="$(post "$req" "$OUT/body")"
  if [ "$status" = 204 ] && [ ! -s "$OUT/body" ]; then
    pass "$name"
  else
    fail "$name" "expected an empty 204, got $status"
  fi
done

for req in "$FIXTURES"/invalid/*.json; do
  name="invalid/$(basename "$req")"
  if lint "$req"; then
    fail "$name" "fixture passes validation, so it tests nothing"
    continue
  fi
  status="$(post "$req" "$OUT/body")"
  if [ "$status" = 200 ] && jq -e '.nbr == 2' "$OUT/body" >/dev/null 2>&1 &&
    lint --type response "$OUT/body"; then
    pass "$name"
  else
    fail "$name" "expected 200 with a valid nbr 2 response, got $status"
  fi
done

for req in "$FIXTURES"/malformed/*; do
  name="malformed/$(basename "$req")"
  status="$(post "$req" "$OUT/body")"
  if [ "$status" = 400 ]; then
    pass "$name"
  else
    fail "$name" "expected 400, got $status"
  fi
done

if [ "$failures" -gt 0 ]; then
  echo "$failures fixture(s) failed"
  exit 1
fi
echo "all fixtures passed"
