|
| 1 | +#!/usr/bin/env bash |
| 2 | +set -Eeuo pipefail |
| 3 | + |
| 4 | +# --------------------------------------------------------------------------- |
| 5 | +# Configuration |
| 6 | +# --------------------------------------------------------------------------- |
| 7 | +MICRO_IMAGE="snowplow/snowplow-micro:latest" |
| 8 | +MICRO_PORT=9090 |
| 9 | +MICRO_CONTAINER_NAME="sp-micro-test" |
| 10 | + |
| 11 | +REFERER_TESTS_FILE="resources/referer-tests.json" |
| 12 | +ENRICHMENTS_DIR="resources/enrichments" |
| 13 | +REFERER_ENRICH_FILE="$ENRICHMENTS_DIR/referer_parser.json" |
| 14 | + |
| 15 | +YAML_REF="resources/referers.yml" |
| 16 | +DB_ASSET="referers.json" |
| 17 | +DB_PORT=8000 |
| 18 | + |
| 19 | +# tracker version kept inline on purpose |
| 20 | +base_event_url="http://localhost:${MICRO_PORT}/com.snowplowanalytics.snowplow/tp2?e=pp&tv=js-0.13.1&p=web" |
| 21 | + |
| 22 | +# --------------------------------------------------------------------------- |
| 23 | +# Helpers |
| 24 | +# --------------------------------------------------------------------------- |
| 25 | +urlencode() { jq -rn --arg v "$1" '$v|@uri'; } |
| 26 | + |
| 27 | +check_deps() { |
| 28 | + local missing=() |
| 29 | + for cmd in "$@"; do |
| 30 | + command -v "$cmd" >/dev/null || missing+=("$cmd") |
| 31 | + done |
| 32 | + if (( ${#missing[@]} )); then |
| 33 | + echo "ERROR: missing command(s): ${missing[*]}" >&2 |
| 34 | + exit 1 |
| 35 | + fi |
| 36 | +} |
| 37 | + |
| 38 | +# --------------------------------------------------------------------------- |
| 39 | +# Dependency checks |
| 40 | +# --------------------------------------------------------------------------- |
| 41 | +check_deps jq docker python3 |
| 42 | + |
| 43 | +# --------------------------------------------------------------------------- |
| 44 | +# Write enrichment configuration |
| 45 | +# --------------------------------------------------------------------------- |
| 46 | +mkdir -p "$ENRICHMENTS_DIR" |
| 47 | +cat > "$REFERER_ENRICH_FILE" <<JSON |
| 48 | +{ |
| 49 | + "schema": "iglu:com.snowplowanalytics.snowplow/referer_parser/jsonschema/2-0-0", |
| 50 | + "data": { |
| 51 | + "name": "referer_parser", |
| 52 | + "vendor": "com.snowplowanalytics.snowplow", |
| 53 | + "enabled": true, |
| 54 | + "parameters": { |
| 55 | + "internalDomains": [], |
| 56 | + "database": "referers.json", |
| 57 | + "uri": "http://host.docker.internal:${DB_PORT}/" |
| 58 | + } |
| 59 | + } |
| 60 | +} |
| 61 | +JSON |
| 62 | + |
| 63 | +# --------------------------------------------------------------------------- |
| 64 | +# Convert YAML DB ➜ JSON |
| 65 | +# --------------------------------------------------------------------------- |
| 66 | +echo "Converting referers.yml to JSON..." |
| 67 | +docker run --rm -i ghcr.io/mikefarah/yq -o=json - < "$YAML_REF" > "$DB_ASSET" |
| 68 | +[[ -s "$DB_ASSET" ]] || { echo "ERROR: yq conversion failed." >&2; exit 1; } |
| 69 | + |
| 70 | +# --------------------------------------------------------------------------- |
| 71 | +# Serve DB over HTTP |
| 72 | +# --------------------------------------------------------------------------- |
| 73 | +echo "Starting local HTTP server on port $DB_PORT..." |
| 74 | +python3 -m http.server "$DB_PORT" --directory "$(dirname "$DB_ASSET")" >/dev/null 2>&1 & |
| 75 | +HTTP_PID=$! |
| 76 | + |
| 77 | +# --------------------------------------------------------------------------- |
| 78 | +# Ensure resources are cleaned up on exit |
| 79 | +# --------------------------------------------------------------------------- |
| 80 | +trap 'kill "$HTTP_PID" 2>/dev/null || true; docker stop "$MICRO_CONTAINER_NAME" >/dev/null 2>&1 || true' EXIT |
| 81 | + |
| 82 | +# --------------------------------------------------------------------------- |
| 83 | +# Launch Snowplow Micro |
| 84 | +# --------------------------------------------------------------------------- |
| 85 | +echo "Starting Snowplow Micro container..." |
| 86 | +docker run -d --rm --name "$MICRO_CONTAINER_NAME" \ |
| 87 | + -p "$MICRO_PORT:9090" \ |
| 88 | + --add-host host.docker.internal:host-gateway \ |
| 89 | + --mount type=bind,source="$(pwd)/$ENRICHMENTS_DIR",destination=/config/enrichments,readonly \ |
| 90 | + "$MICRO_IMAGE" >/dev/null |
| 91 | + |
| 92 | +# --------------------------------------------------------------------------- |
| 93 | +# Wait until /health returns ok |
| 94 | +# --------------------------------------------------------------------------- |
| 95 | +printf "Waiting for Micro to become healthy " |
| 96 | +for _ in {1..30}; do |
| 97 | + if curl -fs "http://localhost:${MICRO_PORT}/health" | grep -qi 'ok'; then |
| 98 | + echo "✓" |
| 99 | + break |
| 100 | + fi |
| 101 | + printf '.' |
| 102 | + sleep 1 |
| 103 | +done || { echo -e "\nERROR: Micro did not become healthy." >&2; exit 1; } |
| 104 | + |
| 105 | +# --------------------------------------------------------------------------- |
| 106 | +# Load test cases (manual loop kept as requested) |
| 107 | +# --------------------------------------------------------------------------- |
| 108 | +echo "Reading test cases..." |
| 109 | +test_cases=() |
| 110 | +while IFS= read -r line; do |
| 111 | + test_cases+=( "$line" ) |
| 112 | +done < <(jq -c '.[]' "$REFERER_TESTS_FILE") |
| 113 | + |
| 114 | +# --------------------------------------------------------------------------- |
| 115 | +# Send events |
| 116 | +# --------------------------------------------------------------------------- |
| 117 | +echo "Sending ${#test_cases[@]} events..." |
| 118 | +for idx in "${!test_cases[@]}"; do |
| 119 | + uri=$(jq -r '.uri' <<< "${test_cases[$idx]}") |
| 120 | + encoded_refr=$(urlencode "$uri") |
| 121 | + curl -s "${base_event_url}&aid=${idx}&refr=${encoded_refr}" >/dev/null |
| 122 | +done |
| 123 | + |
| 124 | +# --------------------------------------------------------------------------- |
| 125 | +# Wait briefly, then fetch processed events |
| 126 | +# --------------------------------------------------------------------------- |
| 127 | +sleep 5 |
| 128 | +good_events=$(curl -s "http://localhost:${MICRO_PORT}/micro/good") |
| 129 | +total_good=$(jq 'length' <<< "$good_events") |
| 130 | +echo "Micro reports $total_good good events." |
| 131 | + |
| 132 | +all_passed=true |
| 133 | +if [[ $total_good -ne ${#test_cases[@]} ]]; then |
| 134 | + echo "❌ Count mismatch (sent ${#test_cases[@]})." |
| 135 | + all_passed=false |
| 136 | +fi |
| 137 | + |
| 138 | +# --------------------------------------------------------------------------- |
| 139 | +# Field‑level validation |
| 140 | +# --------------------------------------------------------------------------- |
| 141 | +if $all_passed; then |
| 142 | + for idx in "${!test_cases[@]}"; do |
| 143 | + tc="${test_cases[$idx]}" |
| 144 | + medium=$(jq -r '.medium' <<< "$tc") |
| 145 | + source=$(jq -r '.source' <<< "$tc") |
| 146 | + uri=$(jq -r '.uri' <<< "$tc") |
| 147 | + |
| 148 | + match=$(jq --arg aid "$idx" --arg m "$medium" --arg s "$source" ' |
| 149 | + .[] | select(.event.app_id==$aid) |
| 150 | + | select(.event.refr_medium==$m and (.event.refr_source // "")==$s)' <<<"$good_events") |
| 151 | + |
| 152 | + if [[ -n $match ]]; then |
| 153 | + echo "✅ $uri" |
| 154 | + else |
| 155 | + echo "❌ $uri – medium/source mismatch" |
| 156 | + all_passed=false |
| 157 | + fi |
| 158 | + done |
| 159 | +fi |
| 160 | + |
| 161 | +# --------------------------------------------------------------------------- |
| 162 | +# Result |
| 163 | +# --------------------------------------------------------------------------- |
| 164 | +if ! $all_passed; then |
| 165 | + echo "Some tests failed." >&2 |
| 166 | + exit 1 |
| 167 | +fi |
| 168 | + |
| 169 | +echo "All tests passed successfully!" |
0 commit comments