reading-list / scripts /smoke.sh
pardeep-singh's picture
Deploy reading-list from main 730966e
06b349d verified
Raw History Blame Contribute Delete
3.58 kB
#!/usr/bin/env bash
# Smoke test for a running Reading List server. curl only.
# Usage: BASE_URL=http://localhost:7860 scripts/smoke.sh
set -euo pipefail
BASE_URL="${BASE_URL:-http://localhost:7860}"
BASE_URL="${BASE_URL%/}"
BODY_FILE="$(mktemp)"
trap 'rm -f "$BODY_FILE"' EXIT
STEP=0
CODE=""
CTYPE=""
BODY=""
pass() { printf 'PASS %d %s\n' "$STEP" "$1"; }
fail() {
printf 'FAIL %d %s\n' "$STEP" "$1" >&2
printf ' got HTTP %s, body: %.300s\n' "$CODE" "$BODY" >&2
exit 1
}
# req METHOD PATH [JSON_BODY] -> sets CODE, CTYPE, BODY
req() {
local method="$1" path="$2" data="${3:-}"
local out
local args=(-sS -o "$BODY_FILE" -w '%{http_code} %{content_type}' -X "$method")
if [[ -n "$data" ]]; then
args+=(-H 'Content-Type: application/json' --data "$data")
fi
STEP=$((STEP + 1))
out="$(curl "${args[@]}" "$BASE_URL$path" 2>&1)" || {
CODE="000"; BODY="$out"; fail "$method $path: could not connect to $BASE_URL"
}
CODE="${out%% *}"
CTYPE="${out#* }"
BODY="$(cat "$BODY_FILE")"
}
# json_int KEY -> first integer value of "KEY" in BODY
json_int() {
printf '%s' "$BODY" | sed -n "s/.*\"$1\"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p" | head -n 1
}
TITLE="Smoke Test $(date +%s)-$$"
echo "Smoke testing $BASE_URL"
# 1. GET / -> 200 HTML
req GET /
[[ "$CODE" == "200" && "$CTYPE" == text/html* ]] || fail "GET / should return 200 text/html (content-type: $CTYPE)"
pass "GET / -> 200 text/html"
# 2. POST a book -> 201
req POST /api/books "{\"title\": \"$TITLE\", \"author\": \"Smoke\", \"status\": \"reading\"}"
[[ "$CODE" == "201" ]] || fail "POST /api/books should return 201"
BOOK_ID="$(json_int id)"
[[ -n "$BOOK_ID" ]] || fail "POST /api/books response has no integer id"
[[ "$BODY" == *"\"$TITLE\""* ]] || fail "POST /api/books response should echo the title"
pass "POST /api/books -> 201 (id $BOOK_ID)"
# 3. GET /api/books?status=reading includes it
req GET "/api/books?status=reading"
[[ "$CODE" == "200" ]] || fail "GET /api/books?status=reading should return 200"
[[ "$BODY" == *"\"$TITLE\""* ]] || fail "GET /api/books?status=reading should include the new book"
pass "GET /api/books?status=reading -> 200, includes new book"
# Stats before the status change
req GET /api/stats
[[ "$CODE" == "200" ]] || fail "GET /api/stats should return 200"
DONE_BEFORE="$(json_int done)"
[[ -n "$DONE_BEFORE" ]] || fail "GET /api/stats should report by_status.done"
pass "GET /api/stats -> 200 (done=$DONE_BEFORE)"
# 4. PATCH its status -> 200
req PATCH "/api/books/$BOOK_ID" '{"status": "done"}'
[[ "$CODE" == "200" ]] || fail "PATCH /api/books/$BOOK_ID should return 200"
[[ "$BODY" == *'"status":"done"'* || "$BODY" == *'"status": "done"'* ]] || fail "PATCH response should have status done"
pass "PATCH /api/books/$BOOK_ID -> 200, status done"
# 5. GET /api/stats reflects the change
req GET /api/stats
[[ "$CODE" == "200" ]] || fail "GET /api/stats should return 200"
DONE_AFTER="$(json_int done)"
[[ "$DONE_AFTER" == "$((DONE_BEFORE + 1))" ]] || fail "by_status.done should go from $DONE_BEFORE to $((DONE_BEFORE + 1)), got '$DONE_AFTER'"
pass "GET /api/stats -> 200 (done=$DONE_AFTER)"
# 6. 422 on blank title
req POST /api/books '{"title": " "}'
[[ "$CODE" == "422" ]] || fail "POST /api/books with a blank title should return 422"
pass "POST /api/books blank title -> 422"
# 7. 404 on PATCH of a missing id
req PATCH /api/books/999999999 '{"status": "done"}'
[[ "$CODE" == "404" ]] || fail "PATCH /api/books/999999999 should return 404"
pass "PATCH /api/books/999999999 -> 404"
echo "All smoke checks passed."