#!/bin/bash # Landing Page Cookbook Test Script # Tests the composable landing page flow from cookbooks/landing-page.md # # Flow: # 1. Create project (monorepo skeleton) # 2. Add app-astro component # 3. Wait for CI pipeline # 4. Verify site is live # # Usage: # ./cookbooks/scripts/landing-test.sh run [name] # Run the full flow # ./cookbooks/scripts/landing-test.sh teardown [name] # Clean up test resources # ./cookbooks/scripts/landing-test.sh status [name] # Check current status set -euo pipefail # Configuration API_URL="${RDEV_API_URL:-https://rdev.masq-ops.orchard9.ai}" API_KEY="${RDEV_API_KEY:?RDEV_API_KEY environment variable required}" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[OK]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } # Timeouts PIPELINE_TIMEOUT=300 # 5 minutes max wait for CI pipeline PIPELINE_POLL_INTERVAL=10 SITE_TIMEOUT=120 # 2 minutes max wait for site to be live api_call() { local method="$1" local endpoint="$2" local data="${3:-}" if [[ -n "$data" ]]; then curl -s -X "$method" "${API_URL}${endpoint}" \ -H "X-API-Key: ${API_KEY}" \ -H "Content-Type: application/json" \ -d "$data" else curl -s -X "$method" "${API_URL}${endpoint}" \ -H "X-API-Key: ${API_KEY}" fi } check_health() { log_info "Checking API health..." local response response=$(curl -s "${API_URL}/health") if echo "$response" | jq -e '.data.status == "ok"' > /dev/null 2>&1; then log_success "API is healthy" return 0 else log_error "API health check failed" echo "$response" | jq . return 1 fi } # Wait for pipeline to appear and complete wait_for_pipeline() { local project_name="$1" local start_time=$(date +%s) local pipeline_found=false local pipeline_number="" local pipeline_status="" log_info "Waiting for CI pipeline to start (timeout: ${PIPELINE_TIMEOUT}s)..." while true; do local elapsed=$(($(date +%s) - start_time)) if [[ $elapsed -ge $PIPELINE_TIMEOUT ]]; then log_error "Pipeline timeout after ${PIPELINE_TIMEOUT}s" return 1 fi local response response=$(api_call GET "/projects/$project_name/pipelines" 2>/dev/null || echo "{}") # Check if we have pipelines local pipeline_count pipeline_count=$(echo "$response" | jq -r '.data | length' 2>/dev/null || echo "0") if [[ "$pipeline_count" -gt 0 ]]; then if [[ "$pipeline_found" == "false" ]]; then pipeline_found=true pipeline_number=$(echo "$response" | jq -r '.data[0].number') log_success "Pipeline #$pipeline_number started" fi # Get latest pipeline status pipeline_status=$(echo "$response" | jq -r '.data[0].status') case "$pipeline_status" in success) echo "" log_success "Pipeline #$pipeline_number completed successfully (${elapsed}s)" return 0 ;; failure|error|killed|declined) echo "" log_error "Pipeline #$pipeline_number failed with status: $pipeline_status" echo "$response" | jq '.data[0]' return 1 ;; running|pending) echo -ne "\r${BLUE}[INFO]${NC} Pipeline #$pipeline_number status: $pipeline_status (${elapsed}s)... " ;; *) echo -ne "\r${BLUE}[INFO]${NC} Pipeline #$pipeline_number status: $pipeline_status (${elapsed}s)... " ;; esac else echo -ne "\r${BLUE}[INFO]${NC} Waiting for pipeline to start (${elapsed}s)... " fi sleep $PIPELINE_POLL_INTERVAL done } # Wait for site to be accessible wait_for_site() { local domain="$1" local start_time=$(date +%s) log_info "Waiting for site to be live: https://$domain (timeout: ${SITE_TIMEOUT}s)..." while true; do local elapsed=$(($(date +%s) - start_time)) if [[ $elapsed -ge $SITE_TIMEOUT ]]; then log_warn "Site timeout after ${SITE_TIMEOUT}s - may still be deploying" return 1 fi local http_code http_code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "https://$domain" 2>/dev/null || echo "000") if [[ "$http_code" == "200" ]]; then echo "" log_success "Site is live! HTTP $http_code (${elapsed}s)" return 0 elif [[ "$http_code" == "000" ]]; then echo -ne "\r${BLUE}[INFO]${NC} Waiting for site... (${elapsed}s, connection failed) " else echo -ne "\r${BLUE}[INFO]${NC} Waiting for site... (${elapsed}s, HTTP $http_code) " fi sleep 3 done } # Main run flow run_flow() { local project_name="$1" echo "" echo "==========================================" echo " Landing Page E2E Test (Composable)" echo "==========================================" echo "" echo "Project: $project_name" echo "" # Step 0: Health check check_health || exit 1 echo "" # Step 1: Create project (monorepo skeleton) log_info "Step 1: Creating project skeleton..." local create_response create_response=$(api_call POST "/projects" "{\"name\": \"$project_name\", \"description\": \"Landing page E2E test\"}") local domain domain=$(echo "$create_response" | jq -r '.data.domain // ""') if [[ -z "$domain" || "$domain" == "null" ]]; then log_error "Failed to create project" echo "$create_response" | jq . exit 1 fi log_success "Project created: $project_name" echo " Domain: $domain" echo " Git: https://git.threesix.ai/jordan/$project_name" echo "" # Step 2: Add app-astro component log_info "Step 2: Adding landing page component (app-astro)..." local component_response component_response=$(api_call POST "/projects/$project_name/components" '{"type": "app", "name": "landing", "template": "app-astro"}') local component_path component_path=$(echo "$component_response" | jq -r '.data.path // ""') if [[ -z "$component_path" || "$component_path" == "null" ]]; then log_error "Failed to add component" echo "$component_response" | jq . exit 1 fi local component_port component_port=$(echo "$component_response" | jq -r '.data.port // "N/A"') log_success "Component added: $component_path (port: $component_port)" echo "" # Step 3: Wait for pipeline log_info "Step 3: Waiting for CI pipeline..." echo "" if ! wait_for_pipeline "$project_name"; then log_warn "Pipeline failed, but continuing to check if site is accessible..." fi echo "" # Step 4: Wait for site log_info "Step 4: Verifying site is accessible..." if wait_for_site "$domain"; then log_success "Site verified!" else log_warn "Site not accessible yet, may need more time" fi echo "" # Summary echo "==========================================" echo " Test Complete" echo "==========================================" echo "" echo " Site URL: https://$domain" echo " Git: https://git.threesix.ai/jordan/$project_name" echo " CI: https://ci.threesix.ai/jordan/$project_name" echo "" echo " To customize: POST /projects/$project_name/builds with a prompt" echo " To teardown: $0 teardown $project_name" echo "" } # Check status check_status() { local project_name="$1" echo "" echo "=== Project Status: $project_name ===" echo "" log_info "Project info:" api_call GET "/projects/$project_name" | jq '.data // .' echo "" log_info "Components:" api_call GET "/projects/$project_name/components" | jq '.data // .' echo "" log_info "Latest pipelines:" api_call GET "/projects/$project_name/pipelines" | jq '.data[:3] // .' echo "" } # Teardown teardown() { local project_name="$1" echo "" log_info "Tearing down project: $project_name" local response response=$(api_call DELETE "/projects/$project_name") if echo "$response" | jq -e '.error' > /dev/null 2>&1; then log_error "Teardown failed" echo "$response" | jq . exit 1 fi log_success "Project deleted (Gitea repo preserved)" echo "$response" | jq '.data // .' echo "" } # Parse command COMMAND="${1:-}" PROJECT_NAME="${2:-landing-test-$(date +%s)}" case "$COMMAND" in run) run_flow "$PROJECT_NAME" ;; status) check_status "$PROJECT_NAME" ;; teardown) teardown "$PROJECT_NAME" ;; *) echo "Landing Page E2E Test Script" echo "" echo "Usage: $0 [project-name]" echo "" echo "Commands:" echo " run Run the full composable landing page flow" echo " status Check project and component status" echo " teardown Delete project (preserves git repo)" echo "" echo "Examples:" echo " $0 run my-landing" echo " $0 status my-landing" echo " $0 teardown my-landing" echo "" exit 1 ;; esac