#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" COMPOSE_FILE="${ROOT_DIR}/docker-compose.yml" BACKEND_URL="${BACKEND_URL:-http://localhost:8000}" WAIT_SECONDS="${WAIT_SECONDS:-60}" PYTHON_BIN="${PYTHON_BIN:-python3}" EDITOR_EMAIL="${EDITOR_EMAIL:-editor@example.com}" cleanup() { docker compose -f "${COMPOSE_FILE}" down --remove-orphans >/dev/null 2>&1 || true } request() { local method="$1" local path="$2" local body="${3:-}" if [[ -n "${body}" ]]; then curl -fsS \ -X "${method}" \ -H "Content-Type: application/json" \ -H "X-Demo-User-Email: ${EDITOR_EMAIL}" \ --data "${body}" \ "${BACKEND_URL}${path}" return fi curl -fsS \ -X "${method}" \ -H "X-Demo-User-Email: ${EDITOR_EMAIL}" \ "${BACKEND_URL}${path}" } wait_backend() { local deadline=$((SECONDS + WAIT_SECONDS)) while (( SECONDS < deadline )); do if curl -fsS "${BACKEND_URL}/health" >/dev/null 2>&1; then return 0 fi sleep 1 done echo "Timed out waiting for backend at ${BACKEND_URL}" >&2 return 1 } extract_json() { local expression="$1" "${PYTHON_BIN}" -c "import json,sys; print(${expression})" } cd "${ROOT_DIR}" trap cleanup EXIT docker compose -f "${COMPOSE_FILE}" up --build -d wait_backend sites_json="$(request GET /api/sites)" site_id="$(printf '%s' "${sites_json}" | extract_json "json.load(sys.stdin)[0]['site']['id']")" article_body="$( SITE_ID="${site_id}" "${PYTHON_BIN}" - <<'PY' import json import os import uuid print(json.dumps({ "target_site_id": os.environ["SITE_ID"], "brief_description": f"Boundary smoke flow {uuid.uuid4()}", "working_title": "Boundary Smoke Flow", "content_type": "longform_guide", "primary_keyword": "boundary smoke flow", })) PY )" article_json="$(request POST /api/articles "${article_body}")" article_id="$(printf '%s' "${article_json}" | extract_json "json.load(sys.stdin)['article']['id']")" questions_json="$(request POST "/api/articles/${article_id}/boundary-questions/generate")" question_patch_commands="$( QUESTIONS_JSON="${questions_json}" "${PYTHON_BIN}" - <<'PY' import json import os import sys payload = json.loads(os.environ["QUESTIONS_JSON"]) for question in payload["questions"]: if question["is_required"]: print(f"{question['id']}\tAccepted answer for {question['category']}.") PY )" while IFS=$'\t' read -r question_id answer; do [[ -z "${question_id}" ]] && continue patch_body="$(ANSWER="${answer}" "${PYTHON_BIN}" - <<'PY' import json import os print(json.dumps({"answer": os.environ["ANSWER"]})) PY )" request PATCH "/api/articles/${article_id}/boundary-questions/${question_id}" "${patch_body}" >/dev/null done <<< "${question_patch_commands}" submitted_json="$(request POST "/api/articles/${article_id}/boundary-questions/submit")" status_value="$(printf '%s' "${submitted_json}" | extract_json "json.load(sys.stdin)['article']['status']")" if [[ "${status_value}" != "BOUNDARY_ANSWERS_SUBMITTED" ]]; then echo "Expected BOUNDARY_ANSWERS_SUBMITTED, got ${status_value}" >&2 exit 1 fi echo "boundary flow smoke ok"