#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" LOCAL_ENV_FILE="${TDC114_SMOKE_ENV_FILE:-$ROOT_DIR/scripts/.env.smoke.local}" if [ -f "$LOCAL_ENV_FILE" ]; then # shellcheck disable=SC1090 source "$LOCAL_ENV_FILE" fi if [ -z "${TDC114_API_BASE:-}" ]; then echo "TDC114_API_BASE is required for API smoke tests." >&2 echo "Example: TDC114_API_BASE=http://127.0.0.1:5000 $0" >&2 if [ -f "$LOCAL_ENV_FILE" ]; then echo "Loaded local smoke env from $LOCAL_ENV_FILE" >&2 fi exit 64 fi if [ "${TDC114_API_BASE:-}" = "https://staging.example.com" ]; then echo "TDC114_API_BASE still points to the example placeholder. Update $LOCAL_ENV_FILE first." >&2 exit 64 fi BASE_URL="${TDC114_API_BASE%/}" AUTH_FLOW="${TDC114_SMOKE_AUTH_FLOW:-phone-login}" TMP_DIR="$(mktemp -d)" trap 'rm -rf "$TMP_DIR"' EXIT request() { local method="$1" local path="$2" local body="${3:-}" local token="${4:-}" local output_file="$TMP_DIR/response" local headers=(-H "Accept: application/json") if [ -n "$token" ]; then headers+=(-H "Authorization: Bearer $token") fi if [ -n "$body" ]; then headers+=(-H "Content-Type: application/json") curl -sS --max-time 10 -o "$output_file" -w "%{http_code}" \ -X "$method" "${headers[@]}" --data "$body" "$BASE_URL$path" else curl -sS --max-time 10 -o "$output_file" -w "%{http_code}" \ -X "$method" "${headers[@]}" "$BASE_URL$path" fi } assert_status() { local name="$1" local actual="$2" shift 2 for expected in "$@"; do if [ "$actual" = "$expected" ]; then echo "PASS $name: HTTP $actual" return 0 fi done echo "FAIL $name: HTTP $actual" >&2 echo "Response body:" >&2 sed -n '1,40p' "$TMP_DIR/response" >&2 exit 1 } extract_json_string() { local key="$1" sed -n "s/.*\"$key\"[[:space:]]*:[[:space:]]*\"\\([^\"]*\\)\".*/\\1/p" "$TMP_DIR/response" | head -n 1 } echo "tdc114plus API smoke: $BASE_URL" status="$(request GET "/api/v1/tdc114plus/directory/employees")" assert_status "unauthorized directory guard" "$status" 401 403 status="$(request POST "/api/v1/tdc114plus/auth/phone-login" '{"phoneNumber":"123","device":{"platform":"smoke","appVersion":"0.1.0","deviceName":"api-smoke"}}')" assert_status "invalid phone-login validation" "$status" 400 status="$(request POST "/api/v1/tdc114plus/auth/link/init" '{"phoneNumber":"123","device":{"platform":"smoke","appVersion":"0.1.0","deviceName":"api-smoke"}}')" assert_status "invalid link-init validation" "$status" 400 status="$(request POST "/api/v1/tdc114plus/auth/link/poll" '{"pendingRef":"api-smoke-missing-ref"}')" assert_status "link-poll expired pendingRef" "$status" 200 if [ "${TDC114_SKIP_AUTH_SMOKE:-false}" = "true" ]; then echo "SKIP authenticated smoke: TDC114_SKIP_AUTH_SMOKE=true" exit 0 fi if [ -z "${TDC114_SMOKE_PHONE:-}" ]; then echo "SKIP authenticated smoke: TDC114_SMOKE_PHONE is not set" exit 0 fi if [ "$AUTH_FLOW" = "link" ]; then login_body="$(printf '{"phoneNumber":"%s","device":{"platform":"smoke","appVersion":"0.1.0","deviceName":"api-smoke"}}' "$TDC114_SMOKE_PHONE")" status="$(request POST "/api/v1/tdc114plus/auth/link/init" "$login_body")" assert_status "link-init success" "$status" 200 pending_ref="$(extract_json_string "pendingRef")" if [ -z "$pending_ref" ]; then echo "FAIL link-init success: pendingRef is missing" >&2 exit 1 fi status="$(request POST "/api/v1/tdc114plus/auth/link/poll" "$(printf '{"pendingRef":"%s"}' "$pending_ref")")" assert_status "link-poll pending" "$status" 200 poll_code="$(extract_json_string "code")" if [ -n "$poll_code" ] && [ "$poll_code" != "authorization_pending" ] && [ "$poll_code" != "slow_down" ]; then echo "FAIL link-poll pending: unexpected code=$poll_code" >&2 sed -n '1,40p' "$TMP_DIR/response" >&2 exit 1 fi echo "PASS staging link smoke: init succeeded and poll is pending" echo "NOTE manual approval is still required to complete end-to-end login." exit 0 fi if [ "$AUTH_FLOW" != "phone-login" ]; then echo "Unknown TDC114_SMOKE_AUTH_FLOW=$AUTH_FLOW" >&2 echo "Expected one of: phone-login, link" >&2 exit 64 fi login_body="$(printf '{"phoneNumber":"%s","device":{"platform":"smoke","appVersion":"0.1.0","deviceName":"api-smoke"}}' "$TDC114_SMOKE_PHONE")" status="$(request POST "/api/v1/tdc114plus/auth/phone-login" "$login_body")" assert_status "phone-login success" "$status" 200 token="$(extract_json_string "token")" if [ -z "$token" ]; then echo "FAIL phone-login success: token is missing" >&2 exit 1 fi status="$(request GET "/api/v1/tdc114plus/directory/employees?limit=10" "" "$token")" assert_status "employee list" "$status" 200 status="$(request GET "/api/v1/tdc114plus/organization/tenants" "" "$token")" assert_status "tenant list" "$status" 200 status="$(request GET "/api/v1/tdc114plus/organization/orgchart" "" "$token")" assert_status "orgchart" "$status" 200