#!/usr/bin/env bash set -euo pipefail BASE_URL="${BASE_URL:-http://127.0.0.1:3000}" DEVICE_FINGERPRINT="${DEVICE_FINGERPRINT:-regression-feature-flags}" FINANCE_MGR_IDENTIFIER="${FINANCE_MGR_IDENTIFIER:-finance_mgr@hyinda.com}" FINANCE_MGR_PASSWORD="${FINANCE_MGR_PASSWORD:-FinanceMgrPassword1234}" if ! command -v curl >/dev/null 2>&1; then echo "[ERROR] curl not found" >&2 exit 1 fi if ! command -v jq >/dev/null 2>&1; then echo "[ERROR] jq not found" >&2 exit 1 fi ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$ROOT_DIR" TMP_DIR="$(mktemp -d)" cleanup() { rm -rf "$TMP_DIR" } trap cleanup EXIT assert_status() { local actual="$1" local expected="$2" local name="$3" local body_file="${4:-}" if [[ "$actual" != "$expected" ]]; then echo "[ERROR] $name expected HTTP $expected but got $actual" >&2 if [[ -n "$body_file" && -f "$body_file" ]]; then cat "$body_file" >&2 fi exit 1 fi } login() { local identifier="$1" local password="$2" local out_file="$3" local status status="$(curl -sS -o "$out_file" -w "%{http_code}" \ -X POST "$BASE_URL/api/auth/login" \ -H "content-type: application/json" \ -H "x-device-fingerprint: $DEVICE_FINGERPRINT" \ -d "{\"identifier\":\"$identifier\",\"password\":\"$password\"}")" assert_status "$status" "200" "login" "$out_file" jq -er '.data.accessToken' "$out_file" } api_json() { local method="$1" local url="$2" local token="$3" local out_file="$4" local body="${5:-}" if [[ -n "$body" ]]; then curl -sS -o "$out_file" -w "%{http_code}" \ -X "$method" "$url" \ -H "authorization: Bearer $token" \ -H "content-type: application/json" \ -d "$body" else curl -sS -o "$out_file" -w "%{http_code}" \ -X "$method" "$url" \ -H "authorization: Bearer $token" fi } echo "[1/4] Login finance_mgr" TOKEN="$(login "$FINANCE_MGR_IDENTIFIER" "$FINANCE_MGR_PASSWORD" "$TMP_DIR/login.json")" echo "[2/4] List feature flags" status="$(api_json GET "$BASE_URL/api/system/feature-flags" "$TOKEN" "$TMP_DIR/list.json")" assert_status "$status" "200" "feature-flags list" "$TMP_DIR/list.json" jq -e '.data.items | length >= 2' "$TMP_DIR/list.json" >/dev/null ERP_VERSION="$(jq -er '.data.items[] | select(.flagKey=="erp_sync") | .version' "$TMP_DIR/list.json")" echo "[3/4] Update erp_sync to force_off/global" status="$(api_json PUT "$BASE_URL/api/system/feature-flags/erp_sync" "$TOKEN" "$TMP_DIR/update.json" "{\"overrideMode\":\"force_off\",\"rolloutType\":\"global\",\"departmentIds\":[],\"note\":\"regression-force-off\",\"expectedVersion\":$ERP_VERSION}")" assert_status "$status" "200" "feature-flags update" "$TMP_DIR/update.json" jq -e '.data.item.flagKey == "erp_sync"' "$TMP_DIR/update.json" >/dev/null jq -e '.data.item.overrideMode == "force_off"' "$TMP_DIR/update.json" >/dev/null echo "[4/4] Verify stale version conflict" status="$(api_json PUT "$BASE_URL/api/system/feature-flags/erp_sync" "$TOKEN" "$TMP_DIR/conflict.json" "{\"overrideMode\":\"force_off\",\"rolloutType\":\"global\",\"departmentIds\":[],\"note\":\"stale-version\",\"expectedVersion\":$ERP_VERSION}")" if [[ "$status" != "409" ]]; then echo "[ERROR] expected version conflict 409 but got $status" >&2 cat "$TMP_DIR/conflict.json" >&2 exit 1 fi echo "[OK] Feature flags regression passed"