#!/bin/bash # Landing Page Cookbook Test Script # Tests the full landing page flow from cookbooks/landing-page.md # # Usage: # ./cookbooks/scripts/landing-test.sh run # Run the full flow # ./cookbooks/scripts/landing-test.sh teardown # Clean up test resources # ./cookbooks/scripts/landing-test.sh status # 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}" PROJECT_NAME="${1:-landing-test}" TEMPLATE="astro-landing" # 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"; } # Configuration for polling PIPELINE_TIMEOUT=300 # 5 minutes max wait for pipeline PIPELINE_POLL_INTERVAL=10 # Check every 10 seconds SITE_TIMEOUT=60 # 1 minute 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 # Returns: 0 on success, 1 on failure/timeout 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 (API returns array at .data, not .data.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) log_success "Pipeline #$pipeline_number completed successfully (${elapsed}s)" return 0 ;; failure|error|killed|declined) 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 # Returns: 0 on success, 1 on failure/timeout 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 } # Test adding a DNS alias test_dns_alias() { local project_name="$1" local alias_domain="$2" log_info "Testing DNS alias: $alias_domain" local response response=$(api_call POST "/projects/$project_name/domains" "{\"domain\": \"$alias_domain\"}") if echo "$response" | jq -e '.error' > /dev/null 2>&1; then local error_code error_code=$(echo "$response" | jq -r '.error.code // "UNKNOWN"') if [[ "$error_code" == "DOMAIN_EXISTS" ]]; then log_warn "Domain alias already exists: $alias_domain" return 0 fi log_error "Failed to add DNS alias" echo "$response" | jq . return 1 fi log_success "DNS alias added: $alias_domain" echo "$response" | jq '.data | {domain, type, dns_record_id}' return 0 } # Remove a DNS alias remove_dns_alias() { local project_name="$1" local alias_domain="$2" log_info "Removing DNS alias: $alias_domain" local response response=$(api_call DELETE "/projects/$project_name/domains/$alias_domain") if echo "$response" | jq -e '.error' > /dev/null 2>&1; then local error_code error_code=$(echo "$response" | jq -r '.error.code // "UNKNOWN"') if [[ "$error_code" == "NOT_FOUND" ]]; then log_warn "Domain alias not found (already deleted?): $alias_domain" return 0 fi log_warn "Failed to remove DNS alias: $alias_domain" return 1 fi log_success "DNS alias removed: $alias_domain" return 0 } run_flow() { local project_name="${1:-landing-test}" local custom_subdomain="${2:-}" echo "" echo "==========================================" echo " Landing Page Cookbook Test" echo " Project: $project_name" if [[ -n "$custom_subdomain" ]]; then echo " Custom subdomain: $custom_subdomain" fi echo "==========================================" echo "" # Step 0: Health check check_health || exit 1 echo "" # Step 1: Create project log_info "Step 1: Creating project with $TEMPLATE template..." local create_payload="{ \"name\": \"$project_name\", \"description\": \"Cookbook test: landing page flow\", \"template\": \"$TEMPLATE\"" if [[ -n "$custom_subdomain" ]]; then create_payload="$create_payload, \"custom_subdomain\": \"$custom_subdomain\"" fi create_payload="$create_payload }" local create_response create_response=$(api_call POST "/project" "$create_payload") if echo "$create_response" | jq -e '.error' > /dev/null 2>&1; then log_error "Failed to create project" echo "$create_response" | jq . exit 1 fi log_success "Project created" echo "$create_response" | jq '{ project_id: .data.project_id, slug: .data.slug, git_url: .data.git.html_url, domain: .data.domain, url: .data.url, domains: .data.domains, next_steps: .data.next_steps }' # Extract domain info local primary_domain local slug primary_domain=$(echo "$create_response" | jq -r '.data.domain') slug=$(echo "$create_response" | jq -r '.data.slug // empty') if [[ -n "$slug" ]]; then log_success "Auto-generated slug: $slug" fi # Check for manual steps local next_steps next_steps=$(echo "$create_response" | jq -r '.data.next_steps[]?' 2>/dev/null || echo "") if [[ -n "$next_steps" ]]; then echo "" log_warn "Some steps require manual intervention:" echo "$create_response" | jq -r '.data.next_steps[]' echo "" log_info "Check API logs for details: ./scripts/logs.sh -e" fi echo "" # Step 2: List all domains log_info "Step 2: Listing all project domains..." local domains_response domains_response=$(api_call GET "/projects/$project_name/domains") if echo "$domains_response" | jq -e '.error' > /dev/null 2>&1; then log_warn "Could not list domains" echo "$domains_response" | jq . else local domain_count domain_count=$(echo "$domains_response" | jq -r '.data.total') log_success "Found $domain_count domain(s)" echo "$domains_response" | jq '.data.domains[] | {domain, type, verified}' fi echo "" # Step 3: Verify project status log_info "Step 3: Verifying project status..." sleep 2 # Give DNS/Gitea a moment local status_response status_response=$(api_call GET "/project/$project_name") if echo "$status_response" | jq -e '.error' > /dev/null 2>&1; then log_warn "Could not fetch project status" echo "$status_response" | jq . else log_success "Project status retrieved" echo "$status_response" | jq '{ name: .data.name, slug: .data.slug, domain: .data.domain, url: .data.url, domains: .data.domains, git: .data.git.html_url, deployment: .data.deployment }' fi echo "" # Step 4: Check DNS log_info "Step 4: Checking DNS resolution..." if host "$primary_domain" > /dev/null 2>&1; then log_success "DNS resolves: $primary_domain" host "$primary_domain" | head -1 else log_warn "DNS not yet resolving: $primary_domain (may take a few minutes)" fi echo "" # Step 5: Wait for CI pipeline log_info "Step 5: Monitoring CI pipeline..." local pipeline_success=false if wait_for_pipeline "$project_name"; then pipeline_success=true else log_warn "Pipeline did not complete successfully - site may not deploy" log_info "Check Woodpecker: https://ci.threesix.ai/threesix/$project_name" fi echo "" # Step 6: Verify site is live (only if pipeline succeeded) local site_live=false if [[ "$pipeline_success" == "true" ]]; then log_info "Step 6: Verifying site is accessible..." if wait_for_site "$primary_domain"; then site_live=true # Show a snippet of the response log_info "Fetching site content preview..." curl -s "https://$primary_domain" | head -20 | grep -E '