#!/bin/bash # Edge cache hit/miss validation (Phase 4 — STREAMING.md cache contract) # Verifies: .m4s segments go MISS→HIT, init.mp4 is cached, .m3u8 refreshes quickly # Usage: ./scripts/validate-edge-cache.sh [base_url] # Default base_url: https://media.linearvoid.tv set -euo pipefail BASE_URL="${1:-https://media.linearvoid.tv}" TIMEOUT=10 FAILURES=0 PASSES=0 green() { echo -e "\033[32m$1\033[0m"; } red() { echo -e "\033[31m$1\033[0m"; } pass() { PASSES=$((PASSES + 1)); green " ✓ PASS: $1"; } fail() { FAILURES=$((FAILURES + 1)); red " ✗ FAIL: $1"; } # Fetch a header from a URL fetch_header() { local url="$1" header="$2" curl -sI --connect-timeout "$TIMEOUT" --max-time "$TIMEOUT" "$url" 2>/dev/null | \ grep -i "^${header}:" | sed 's/.*: //' | tr -d '\r' || echo "" } echo "=== Edge Cache Validation ===" echo "Target: $BASE_URL" echo "" # 1. Get current playlist manifest and extract a segment name echo "--- Test 1: Manifest freshness ---" MANIFEST_URL="$BASE_URL/hls/playlist.m3u8" MANIFEST=$(curl -s --connect-timeout "$TIMEOUT" --max-time "$TIMEOUT" "$MANIFEST_URL" 2>/dev/null || echo "") if [[ -z "$MANIFEST" ]]; then fail "Manifest is empty or unreachable" else if echo "$MANIFEST" | grep -q "#EXTM3U"; then pass "Manifest is valid M3U8" else fail "Manifest missing #EXTM3U header" fi fi SEGMENT=$(echo "$MANIFEST" | grep "\.m4s" | tail -1 | tr -d '\r') if [[ -z "$SEGMENT" ]]; then fail "No .m4s segment found in manifest" else pass "Found segment: $SEGMENT" fi # 2. Test manifest Cache-Control MANIFEST_CC=$(fetch_header "$MANIFEST_URL" "Cache-Control") echo "" echo "--- Test 2: Manifest Cache-Control ---" if echo "$MANIFEST_CC" | grep -q "must-revalidate"; then pass "Manifest has must-revalidate ($MANIFEST_CC)" else fail "Manifest missing must-revalidate ($MANIFEST_CC)" fi if echo "$MANIFEST_CC" | grep -q "max-age"; then pass "Manifest has max-age ($MANIFEST_CC)" else fail "Manifest missing max-age ($MANIFEST_CC)" fi # 3. Test segment cache (MISS → HIT) if [[ -n "$SEGMENT" ]]; then SEGMENT_URL="$BASE_URL/hls/$SEGMENT" echo "" echo "--- Test 3: Segment cache MISS→HIT ---" FIRST_STATUS=$(fetch_header "$SEGMENT_URL" "CF-Cache-Status") echo " First request: CF-Cache-Status=$FIRST_STATUS" sleep 1 SECOND_STATUS=$(fetch_header "$SEGMENT_URL" "CF-Cache-Status") echo " Second request: CF-Cache-Status=$SECOND_STATUS" if [[ "$SECOND_STATUS" == "HIT" ]]; then pass "Segment cache HIT on second request (was $FIRST_STATUS)" elif [[ "$FIRST_STATUS" == "HIT" ]]; then pass "Segment already cached (HIT on first request)" else fail "Segment not cached: first=$FIRST_STATUS, second=$SECOND_STATUS" fi fi # 4. Test segment Cache-Control (immutable) if [[ -n "$SEGMENT" ]]; then echo "" echo "--- Test 4: Segment immutable cache ---" SEGMENT_CC=$(fetch_header "$SEGMENT_URL" "Cache-Control") if echo "$SEGMENT_CC" | grep -q "immutable"; then pass "Segment has immutable ($SEGMENT_CC)" else fail "Segment missing immutable ($SEGMENT_CC)" fi if echo "$SEGMENT_CC" | grep -q "max-age=31536000"; then pass "Segment has 1-year max-age ($SEGMENT_CC)" else fail "Segment missing 1-year max-age ($SEGMENT_CC)" fi fi # 5. Test init.mp4 cache echo "" echo "--- Test 5: Init segment cache ---" INIT_URL="$BASE_URL/hls/init.mp4" INIT_STATUS=$(fetch_header "$INIT_URL" "CF-Cache-Status") INIT_CC=$(fetch_header "$INIT_URL" "Cache-Control") if [[ "$INIT_STATUS" == "HIT" ]]; then pass "Init segment cached (CF-Cache-Status=$INIT_STATUS, CC=$INIT_CC)" else fail "Init segment not cached: $INIT_STATUS" fi # 6. Test manifest refresh (should NOT be cached long-term) echo "" echo "--- Test 6: Manifest refresh rate ---" MANIFEST_CF=$(fetch_header "$MANIFEST_URL" "CF-Cache-Status") echo " Manifest CF-Cache-Status: $MANIFEST_CF" # DYNAMIC or BYPASS is correct for live manifests. HIT with long TTL is wrong. if [[ "$MANIFEST_CF" == "DYNAMIC" ]] || [[ "$MANIFEST_CF" == "BYPASS" ]] || [[ "$MANIFEST_CF" == "MISS" ]] || [[ "$MANIFEST_CF" == "REVALIDATED" ]]; then pass "Manifest not long-term cached ($MANIFEST_CF)" elif [[ "$MANIFEST_CF" == "HIT" ]]; then fail "Manifest is HIT — may be stale (check TTL)" else pass "Manifest status: $MANIFEST_CF (no HIT = acceptable)" fi # Summary echo "" echo "=== Results: $PASSES passed, $FAILURES failed ===" if [[ $FAILURES -gt 0 ]]; then exit 1 fi exit 0