#!/usr/bin/env bash set -Eeuo pipefail # === Settings === BASE_URL="${BASE_URL:-http://localhost:8080}" AUTH="$BASE_URL/auth" PROFILES="$BASE_URL/profiles" # Можно переопределить через окружение: EMAIL="${EMAIL:-user+$(date +%s)@example.com}" PASS="${PASS:-secret123}" FULL_NAME="${FULL_NAME:-Demo User}" ROLE="${ROLE:-CLIENT}" # Куда писать лог (по умолчанию в logs/) mkdir -p logs TS="$(date +%Y%m%d_%H%M%S)" LOG_FILE="${LOG_FILE:-logs/user_flow_${TS}.log}" # Вспомогательные утилиты have_jq=0; command -v jq >/dev/null 2>&1 && have_jq=1 log() { echo "[$(date +'%F %T')] $*" | tee -a "$LOG_FILE" >&2; } hr() { printf -- '-----\n' | tee -a "$LOG_FILE" >/dev/null; } # Выполнить HTTP и вернуть: | http_req() { local METHOD="$1"; shift local URL="$1"; shift local TOKEN="${1:-}"; shift || true local BODY="${1:-}"; shift || true local RESP_FILE; RESP_FILE="$(mktemp)" local args=(-sS --connect-timeout 10 --max-time 30 -X "$METHOD" "$URL" -o "$RESP_FILE" -w "%{http_code}") [[ -n "$TOKEN" ]] && args+=(-H "Authorization: Bearer $TOKEN") [[ -n "$BODY" ]] && args+=(-H "Content-Type: application/json" -d "$BODY") local CODE; CODE="$(curl "${args[@]}" || true)" echo "${CODE}|${RESP_FILE}" } # Красиво положить ответ в лог log_response() { local title="$1"; shift local code="$1"; shift local body_file="$1"; shift hr log "$title" log "URL: ${CURRENT_URL}" log "HTTP: ${code}" if [[ $have_jq -eq 1 ]]; then log "Body:" jq . "$body_file" 2>/dev/null | tee -a "$LOG_FILE" >/dev/null || cat "$body_file" | tee -a "$LOG_FILE" >/dev/null else log "Body (raw):" cat "$body_file" | tee -a "$LOG_FILE" >/dev/null fi } # Достаём поле из JSON (без jq) json_get() { local file="$1"; shift local path="$1"; shift python3 - "$file" "$path" <<'PY' import sys, json fn, path = sys.argv[1], sys.argv[2] try: data = json.load(open(fn, 'rb')) except Exception: print('') sys.exit(0) cur = data for k in path.split('.'): if isinstance(cur, list): try: k = int(k) except Exception: print(''); sys.exit(0) if 0 <= k < len(cur): cur = cur[k] else: print(''); sys.exit(0) elif isinstance(cur, dict): cur = cur.get(k) else: print(''); sys.exit(0) if cur is None: print(''); sys.exit(0) if isinstance(cur, (dict, list)): print(json.dumps(cur)) else: print(cur) PY } echo "== Log file: ${LOG_FILE} ==" >&2 hr log "BASE_URL: ${BASE_URL}" log "EMAIL: ${EMAIL}" log "FULL_NAME: ${FULL_NAME}" log "ROLE: ${ROLE}" # 1) REGISTER BODY_REG=$(printf '{"email":"%s","password":"%s","full_name":"%s","role":"%s"}' "$EMAIL" "$PASS" "$FULL_NAME" "$ROLE") CURRENT_URL="$AUTH/v1/register" resp="$(http_req POST "$CURRENT_URL" "" "$BODY_REG")" code="${resp%%|*}"; body="${resp##*|}" log_response "REGISTER" "$code" "$body" if [[ "$code" != "201" && "$code" != "200" ]]; then # если уже существует — ок, продолжаем detail="$(json_get "$body" "detail" || true)" if [[ "$code" == "400" && "$detail" == "Email already in use" ]]; then log "Register: email already exists — continue to login" else log "Register non-success: ${code} — continue to login anyway" fi fi # 2) LOGIN (TOKEN) BODY_LOGIN=$(printf '{"email":"%s","password":"%s"}' "$EMAIL" "$PASS") CURRENT_URL="$AUTH/v1/token" resp="$(http_req POST "$CURRENT_URL" "" "$BODY_LOGIN")" code="${resp%%|*}"; body="${resp##*|}" log_response "LOGIN / TOKEN" "$code" "$body" if [[ "$code" != "200" ]]; then log "ERROR: login failed with $code" exit 1 fi ACCESS_TOKEN="$(json_get "$body" "access_token")" if [[ -z "$ACCESS_TOKEN" ]]; then log "ERROR: access_token not found in login response" exit 1 fi log "Got access_token (hidden)" hr # 3) GET PROFILE (me) CURRENT_URL="$PROFILES/v1/profiles/me" resp="$(http_req GET "$CURRENT_URL" "$ACCESS_TOKEN")" code="${resp%%|*}"; body="${resp##*|}" log_response "GET /profiles/me" "$code" "$body" if [[ "$code" == "404" ]]; then log "Profile not found — creating…" # 3a) CREATE PROFILE (минимальный) BODY_CREATE='{"gender":"other","city":"Moscow","languages":["ru","en"],"interests":["music","travel"]}' CURRENT_URL="$PROFILES/v1/profiles" resp="$(http_req POST "$CURRENT_URL" "$ACCESS_TOKEN" "$BODY_CREATE")" code="${resp%%|*}"; body="${resp##*|}" log_response "CREATE /profiles" "$code" "$body" if [[ "$code" != "201" && "$code" != "200" ]]; then log "ERROR: create profile failed with $code" exit 1 fi # 3b) GET PROFILE AGAIN CURRENT_URL="$PROFILES/v1/profiles/me" resp="$(http_req GET "$CURRENT_URL" "$ACCESS_TOKEN")" code="${resp%%|*}"; body="${resp##*|}" log_response "GET /profiles/me (after create)" "$code" "$body" if [[ "$code" != "200" ]]; then log "ERROR: expected 200 after create, got $code" exit 1 fi elif [[ "$code" != "200" ]]; then log "ERROR: unexpected code for /profiles/me: $code" exit 1 fi log "DONE. Log saved to: ${LOG_FILE}"