#!/bin/bash # ThrillWiki Hybrid Filtering Endpoints Test Script # Tests the newly synchronized Parks and Rides hybrid filtering endpoints # # Usage: ./test_hybrid_endpoints.sh [BASE_URL] # Default BASE_URL: http://localhost:8000 set -e # Configuration BASE_URL="${1:-http://localhost:8000}" VERBOSE=true # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[1;33m' PURPLE='\033[0;35m' CYAN='\033[0;36m' NC='\033[0m' # No Color # Helper functions print_header() { local title="$1" local level="${2:-1}" case $level in 1) echo -e "\n${BLUE}================================================================================${NC}" echo -e "${BLUE}$title${NC}" echo -e "${BLUE}================================================================================${NC}" ;; 2) echo -e "\n${CYAN}--------------------------------------------------------------------------------${NC}" echo -e "${CYAN}$title${NC}" echo -e "${CYAN}--------------------------------------------------------------------------------${NC}" ;; 3) echo -e "\n${YELLOW}$title${NC}" echo -e "${YELLOW}$(echo "$title" | sed 's/./~/g')${NC}" ;; esac } print_endpoint() { local method="$1" local url="$2" echo -e "\n${PURPLE}🔗 ENDPOINT:${NC} ${GREEN}$method${NC} $url" } print_description() { local desc="$1" echo -e "${CYAN}📋 DESCRIPTION:${NC} $desc" } make_request() { local method="$1" local url="$2" local description="$3" print_endpoint "$method" "$url" print_description "$description" echo -e "\n${YELLOW}📤 REQUEST:${NC}" echo "curl -X $method \\" echo " -H 'Accept: application/json' \\" echo " -H 'Content-Type: application/json' \\" echo " '$url'" echo -e "\n${YELLOW}📥 RESPONSE:${NC}" # Make the actual request response=$(curl -s -w "\n%{http_code}" -X "$method" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ "$url") # Extract status code and body status_code=$(echo "$response" | tail -n1) body=$(echo "$response" | sed '$d') # Print status if [[ "$status_code" -ge 200 && "$status_code" -lt 300 ]]; then echo -e "${GREEN}✅ SUCCESS: HTTP $status_code${NC}" else echo -e "${RED}❌ ERROR: HTTP $status_code${NC}" fi # Pretty print JSON response if command -v jq >/dev/null 2>&1; then echo "$body" | jq '.' else echo "$body" fi # Extract and display key metrics if command -v jq >/dev/null 2>&1 && [[ "$status_code" -ge 200 && "$status_code" -lt 300 ]]; then echo -e "\n${CYAN}📊 RESPONSE SUMMARY:${NC}" # Total count total_count=$(echo "$body" | jq -r '.total_count // empty') if [[ -n "$total_count" ]]; then echo -e " • Total Count: ${GREEN}$total_count${NC}" fi # Strategy strategy=$(echo "$body" | jq -r '.strategy // empty') if [[ -n "$strategy" ]]; then if [[ "$strategy" == "client_side" ]]; then echo -e " • Strategy: ${GREEN}🖥️ $strategy${NC}" else echo -e " • Strategy: ${BLUE}🌐 $strategy${NC}" fi fi # Has more has_more=$(echo "$body" | jq -r '.has_more // empty') if [[ -n "$has_more" ]]; then if [[ "$has_more" == "true" ]]; then echo -e " • Has More: ${YELLOW}➡️ $has_more${NC}" else echo -e " • Has More: ${GREEN}🏁 $has_more${NC}" fi fi # Next offset next_offset=$(echo "$body" | jq -r '.next_offset // empty') if [[ -n "$next_offset" && "$next_offset" != "null" ]]; then echo -e " • Next Offset: ${CYAN}$next_offset${NC}" fi # Data counts parks_count=$(echo "$body" | jq -r '.parks | length // empty' 2>/dev/null) if [[ -n "$parks_count" ]]; then echo -e " • Parks Returned: ${GREEN}$parks_count${NC}" fi rides_count=$(echo "$body" | jq -r '.rides | length // empty' 2>/dev/null) if [[ -n "$rides_count" ]]; then echo -e " • Rides Returned: ${GREEN}$rides_count${NC}" fi # Filter metadata summary if echo "$body" | jq -e '.filter_metadata' >/dev/null 2>&1; then echo -e " • Filter Metadata: ${GREEN}✅ Available${NC}" # Count categorical options countries=$(echo "$body" | jq -r '.filter_metadata.categorical.countries | length // 0' 2>/dev/null) states=$(echo "$body" | jq -r '.filter_metadata.categorical.states | length // 0' 2>/dev/null) categories=$(echo "$body" | jq -r '.filter_metadata.categorical.categories | length // 0' 2>/dev/null) if [[ "$countries" -gt 0 ]]; then echo -e " - Countries: ${CYAN}$countries${NC}" fi if [[ "$states" -gt 0 ]]; then echo -e " - States: ${CYAN}$states${NC}" fi if [[ "$categories" -gt 0 ]]; then echo -e " - Categories: ${CYAN}$categories${NC}" fi fi fi echo -e "\n${PURPLE}$(printf '%.0s-' {1..80})${NC}" } # Main test execution main() { print_header "THRILLWIKI HYBRID FILTERING ENDPOINTS TEST SUITE" 1 echo -e "Testing endpoints at: ${GREEN}$BASE_URL${NC}" echo -e "Timestamp: ${CYAN}$(date)${NC}" # Check if server is running echo -e "\n${YELLOW}🔍 Checking server availability...${NC}" if ! curl -s --connect-timeout 5 "$BASE_URL" >/dev/null; then echo -e "${RED}❌ Server not available at $BASE_URL${NC}" echo -e "${YELLOW}💡 Make sure to start the Django server first:${NC}" echo -e " cd backend && uv run manage.py runserver_plus" exit 1 fi echo -e "${GREEN}✅ Server is running${NC}" # ======================================================================== # PARKS HYBRID FILTERING TESTS # ======================================================================== print_header "PARKS HYBRID FILTERING TESTS" 1 # Test 1: Basic Parks Hybrid Filtering make_request "GET" \ "$BASE_URL/api/v1/parks/hybrid/" \ "Basic hybrid filtering with no parameters - demonstrates automatic strategy selection" # Test 2: Parks with Search Filter make_request "GET" \ "$BASE_URL/api/v1/parks/hybrid/?search=disney" \ "Search for parks containing 'disney' - tests full-text search functionality" # Test 3: Parks with Status Filter make_request "GET" \ "$BASE_URL/api/v1/parks/hybrid/?status=OPERATING,CLOSED_TEMP" \ "Filter parks by multiple statuses - tests comma-separated list parameters" # Test 4: Parks with Geographic Filters make_request "GET" \ "$BASE_URL/api/v1/parks/hybrid/?country=United%20States&state=Florida,California" \ "Filter parks by country and multiple states - tests geographic filtering" # Test 5: Parks with Numeric Range Filters make_request "GET" \ "$BASE_URL/api/v1/parks/hybrid/?opening_year_min=1990&opening_year_max=2020&rating_min=4.0" \ "Filter parks by opening year range and minimum rating - tests numeric range filtering" # Test 6: Parks with Size and Ride Count Filters make_request "GET" \ "$BASE_URL/api/v1/parks/hybrid/?size_min=100&ride_count_min=10&coaster_count_min=5" \ "Filter parks by minimum size, ride count, and coaster count - tests park statistics filtering" # Test 7: Parks with Operator Filter make_request "GET" \ "$BASE_URL/api/v1/parks/hybrid/?operator=disney,universal" \ "Filter parks by operator slugs - tests company relationship filtering" # Test 8: Parks Progressive Loading (with offset) make_request "GET" \ "$BASE_URL/api/v1/parks/hybrid/?offset=50" \ "Progressive loading starting at offset 50 - tests server-side pagination" # Test 9: Parks Filter Metadata make_request "GET" \ "$BASE_URL/api/v1/parks/hybrid/filter-metadata/" \ "Get comprehensive filter metadata for parks - provides all available filter options and ranges" # Test 10: Parks Scoped Filter Metadata make_request "GET" \ "$BASE_URL/api/v1/parks/hybrid/filter-metadata/?scoped=true&country=United%20States" \ "Get filter metadata scoped to US parks - demonstrates dynamic metadata based on current filters" # ======================================================================== # RIDES HYBRID FILTERING TESTS # ======================================================================== print_header "RIDES HYBRID FILTERING TESTS" 1 # Test 1: Basic Rides Hybrid Filtering make_request "GET" \ "$BASE_URL/api/v1/rides/hybrid/" \ "Basic hybrid filtering with no parameters - demonstrates automatic strategy selection for rides" # Test 2: Rides with Search Filter make_request "GET" \ "$BASE_URL/api/v1/rides/hybrid/?search=coaster" \ "Search for rides containing 'coaster' - tests full-text search across ride names and descriptions" # Test 3: Rides with Category Filter make_request "GET" \ "$BASE_URL/api/v1/rides/hybrid/?category=RC,DR" \ "Filter rides by categories (Roller Coaster, Dark Ride) - tests ride category filtering" # Test 4: Rides with Status and Park Filters make_request "GET" \ "$BASE_URL/api/v1/rides/hybrid/?status=OPERATING&park_slug=cedar-point" \ "Filter operating rides at Cedar Point - tests status and park-specific filtering" # Test 5: Rides with Manufacturer and Designer Filters make_request "GET" \ "$BASE_URL/api/v1/rides/hybrid/?manufacturer=bolliger-mabillard&designer=bolliger-mabillard" \ "Filter rides by B&M as manufacturer and designer - tests company relationship filtering" # Test 6: Rides with Roller Coaster Specific Filters make_request "GET" \ "$BASE_URL/api/v1/rides/hybrid/?roller_coaster_type=INVERTED,FLYING&track_material=STEEL&has_inversions=true" \ "Filter inverted/flying steel coasters with inversions - tests roller coaster specific attributes" # Test 7: Rides with Height and Speed Filters make_request "GET" \ "$BASE_URL/api/v1/rides/hybrid/?height_ft_min=200&speed_mph_min=70&inversions_min=4" \ "Filter tall, fast coasters with multiple inversions - tests numeric performance filtering" # Test 8: Rides with Rating and Capacity Filters make_request "GET" \ "$BASE_URL/api/v1/rides/hybrid/?rating_min=4.5&capacity_min=1000&opening_year_min=2000" \ "Filter highly-rated, high-capacity modern rides - tests quality and operational metrics" # Test 9: Rides with Height Requirement Filters make_request "GET" \ "$BASE_URL/api/v1/rides/hybrid/?height_requirement_min=48&height_requirement_max=54" \ "Filter rides by height requirements (48-54 inches) - tests accessibility filtering" # Test 10: Rides Progressive Loading make_request "GET" \ "$BASE_URL/api/v1/rides/hybrid/?offset=25&category=RC" \ "Progressive loading of roller coasters starting at offset 25 - tests server-side pagination with filters" # Test 11: Rides Filter Metadata make_request "GET" \ "$BASE_URL/api/v1/rides/hybrid/filter-metadata/" \ "Get comprehensive filter metadata for rides - provides all available filter options and ranges" # Test 12: Rides Scoped Filter Metadata make_request "GET" \ "$BASE_URL/api/v1/rides/hybrid/filter-metadata/?scoped=true&category=RC" \ "Get filter metadata scoped to roller coasters - demonstrates dynamic metadata for specific categories" # ======================================================================== # COMPLEX COMBINATION TESTS # ======================================================================== print_header "COMPLEX COMBINATION TESTS" 1 # Test 1: Parks with All Filter Types make_request "GET" \ "$BASE_URL/api/v1/parks/hybrid/?search=theme&status=OPERATING&country=United%20States&opening_year_min=1980&rating_min=4.0&size_min=50&ride_count_min=20" \ "Complex parks query combining search, status, geographic, temporal, rating, and size filters" # Test 2: Rides with All Filter Types make_request "GET" \ "$BASE_URL/api/v1/rides/hybrid/?search=steel&category=RC&status=OPERATING&roller_coaster_type=SITDOWN&track_material=STEEL&height_ft_min=100&speed_mph_min=50&rating_min=4.0&has_inversions=false" \ "Complex rides query combining search, category, status, coaster type, materials, performance, and rating filters" # ======================================================================== # EDGE CASE TESTS # ======================================================================== print_header "EDGE CASE TESTS" 1 # Test 1: Empty Results make_request "GET" \ "$BASE_URL/api/v1/parks/hybrid/?search=nonexistentpark12345" \ "Search for non-existent park - tests empty result handling" # Test 2: Invalid Parameters make_request "GET" \ "$BASE_URL/api/v1/rides/hybrid/?height_ft_min=invalid&rating_min=15" \ "Invalid numeric parameters - tests parameter validation and error handling" # Test 3: Large Offset make_request "GET" \ "$BASE_URL/api/v1/parks/hybrid/?offset=99999" \ "Very large offset value - tests pagination boundary handling" # ======================================================================== # PERFORMANCE COMPARISON TESTS # ======================================================================== print_header "PERFORMANCE COMPARISON TESTS" 1 echo -e "\n${CYAN}📊 Testing response times for different strategies...${NC}" # Time the requests echo -e "\n${YELLOW}⏱️ Timing Parks Hybrid Endpoint:${NC}" time curl -s -o /dev/null "$BASE_URL/api/v1/parks/hybrid/" echo -e "\n${YELLOW}⏱️ Timing Rides Hybrid Endpoint:${NC}" time curl -s -o /dev/null "$BASE_URL/api/v1/rides/hybrid/" echo -e "\n${YELLOW}⏱️ Timing Parks Filter Metadata:${NC}" time curl -s -o /dev/null "$BASE_URL/api/v1/parks/hybrid/filter-metadata/" echo -e "\n${YELLOW}⏱️ Timing Rides Filter Metadata:${NC}" time curl -s -o /dev/null "$BASE_URL/api/v1/rides/hybrid/filter-metadata/" # ======================================================================== # SUMMARY # ======================================================================== print_header "TEST SUITE SUMMARY" 1 echo -e "${GREEN}✅ Test suite completed successfully!${NC}" echo -e "\n${CYAN}📋 ENDPOINTS TESTED:${NC}" echo -e " • Parks Hybrid Filtering: ${GREEN}/api/v1/parks/hybrid/${NC}" echo -e " • Parks Filter Metadata: ${GREEN}/api/v1/parks/hybrid/filter-metadata/${NC}" echo -e " • Rides Hybrid Filtering: ${GREEN}/api/v1/rides/hybrid/${NC}" echo -e " • Rides Filter Metadata: ${GREEN}/api/v1/rides/hybrid/filter-metadata/${NC}" echo -e "\n${CYAN}🔍 KEY FEATURES DEMONSTRATED:${NC}" echo -e " • Automatic strategy selection (client-side vs server-side)" echo -e " • Progressive loading for large datasets" echo -e " • Comprehensive filter options (17+ parameters per domain)" echo -e " • Dynamic filter metadata generation" echo -e " • Consistent response formats across domains" echo -e " • Full-text search capabilities" echo -e " • Numeric range filtering" echo -e " • Multi-value parameter support" echo -e " • Geographic and temporal filtering" echo -e " • Roller coaster specific filtering" echo -e " • Error handling and validation" echo -e "\n${YELLOW}💡 NEXT STEPS:${NC}" echo -e " • Integrate these endpoints into your frontend application" echo -e " • Use filter metadata to build dynamic filter interfaces" echo -e " • Implement progressive loading for better user experience" echo -e " • Monitor performance and adjust thresholds as needed" echo -e "\n${PURPLE}🎉 Happy filtering! 🎢${NC}" } # Check dependencies check_dependencies() { if ! command -v curl >/dev/null 2>&1; then echo -e "${RED}❌ curl is required but not installed${NC}" exit 1 fi if ! command -v jq >/dev/null 2>&1; then echo -e "${YELLOW}⚠️ jq not found - JSON responses will not be pretty-printed${NC}" fi } # Script execution check_dependencies main "$@"