# Phase 5: Testing & Validation ## Overview This phase provides comprehensive testing procedures to validate that the Vehicle ETL integration meets all performance, accuracy, and reliability requirements. Testing covers API functionality, performance benchmarks, data accuracy, and system reliability. ## Prerequisites - All previous phases (1-4) completed successfully - MVP Platform database populated with vehicle data - All API endpoints functional - ETL scheduler running and operational - Backend service connected to MVP Platform database ## Success Criteria Review Before starting tests, review the success criteria: - ✅ **Zero Breaking Changes**: All existing vehicle functionality unchanged - ✅ **Performance**: Dropdown APIs maintain < 100ms response times - ✅ **Accuracy**: VIN decoding matches current NHTSA accuracy (99.9%+) - ✅ **Reliability**: Weekly ETL completes successfully with error handling - ✅ **Scalability**: Clean two-database architecture ready for additional platform services ## Testing Categories ### Category 1: API Functionality Testing ### Category 2: Performance Testing ### Category 3: Data Accuracy Validation ### Category 4: ETL Process Testing ### Category 5: Error Handling & Recovery ### Category 6: Load Testing ### Category 7: Security Validation --- ## Category 1: API Functionality Testing ### Test 1.1: Dropdown API Response Formats **Purpose**: Verify all dropdown endpoints return data in the exact same format as before **Test Script**: `test-api-formats.sh` ```bash #!/bin/bash echo "=== API Format Validation Tests ===" # Test makes endpoint echo "Testing /api/vehicles/dropdown/makes..." MAKES_RESPONSE=$(curl -s http://localhost:3001/api/vehicles/dropdown/makes) MAKES_COUNT=$(echo "$MAKES_RESPONSE" | jq '. | length') if [ "$MAKES_COUNT" -gt 0 ]; then # Check first item has correct format FIRST_MAKE=$(echo "$MAKES_RESPONSE" | jq '.[0]') if echo "$FIRST_MAKE" | jq -e '.Make_ID and .Make_Name' > /dev/null; then echo "✅ Makes format correct" else echo "❌ Makes format incorrect: $FIRST_MAKE" exit 1 fi else echo "❌ No makes returned" exit 1 fi # Test models endpoint echo "Testing /api/vehicles/dropdown/models/:make..." FIRST_MAKE_NAME=$(echo "$MAKES_RESPONSE" | jq -r '.[0].Make_Name') MODELS_RESPONSE=$(curl -s "http://localhost:3001/api/vehicles/dropdown/models/$FIRST_MAKE_NAME") MODELS_COUNT=$(echo "$MODELS_RESPONSE" | jq '. | length') if [ "$MODELS_COUNT" -gt 0 ]; then FIRST_MODEL=$(echo "$MODELS_RESPONSE" | jq '.[0]') if echo "$FIRST_MODEL" | jq -e '.Model_ID and .Model_Name' > /dev/null; then echo "✅ Models format correct" else echo "❌ Models format incorrect: $FIRST_MODEL" exit 1 fi else echo "⚠️ No models for $FIRST_MAKE_NAME (may be expected)" fi # Test transmissions endpoint echo "Testing /api/vehicles/dropdown/transmissions..." TRANS_RESPONSE=$(curl -s http://localhost:3001/api/vehicles/dropdown/transmissions) TRANS_COUNT=$(echo "$TRANS_RESPONSE" | jq '. | length') if [ "$TRANS_COUNT" -gt 0 ]; then FIRST_TRANS=$(echo "$TRANS_RESPONSE" | jq '.[0]') if echo "$FIRST_TRANS" | jq -e '.Name' > /dev/null; then echo "✅ Transmissions format correct" else echo "❌ Transmissions format incorrect: $FIRST_TRANS" exit 1 fi else echo "❌ No transmissions returned" exit 1 fi # Test engines endpoint echo "Testing /api/vehicles/dropdown/engines..." ENGINES_RESPONSE=$(curl -s http://localhost:3001/api/vehicles/dropdown/engines) ENGINES_COUNT=$(echo "$ENGINES_RESPONSE" | jq '. | length') if [ "$ENGINES_COUNT" -gt 0 ]; then FIRST_ENGINE=$(echo "$ENGINES_RESPONSE" | jq '.[0]') if echo "$FIRST_ENGINE" | jq -e '.Name' > /dev/null; then echo "✅ Engines format correct" else echo "❌ Engines format incorrect: $FIRST_ENGINE" exit 1 fi else echo "❌ No engines returned" exit 1 fi # Test trims endpoint echo "Testing /api/vehicles/dropdown/trims..." TRIMS_RESPONSE=$(curl -s http://localhost:3001/api/vehicles/dropdown/trims) TRIMS_COUNT=$(echo "$TRIMS_RESPONSE" | jq '. | length') if [ "$TRIMS_COUNT" -gt 0 ]; then FIRST_TRIM=$(echo "$TRIMS_RESPONSE" | jq '.[0]') if echo "$FIRST_TRIM" | jq -e '.Name' > /dev/null; then echo "✅ Trims format correct" else echo "❌ Trims format incorrect: $FIRST_TRIM" exit 1 fi else echo "❌ No trims returned" exit 1 fi echo "✅ All API format tests passed" ``` ### Test 1.2: Authentication Validation **Purpose**: Ensure dropdown endpoints remain unauthenticated while CRUD endpoints require authentication **Test Script**: `test-authentication.sh` ```bash #!/bin/bash echo "=== Authentication Validation Tests ===" # Test dropdown endpoints are unauthenticated echo "Testing dropdown endpoints without authentication..." ENDPOINTS=( "/api/vehicles/dropdown/makes" "/api/vehicles/dropdown/transmissions" "/api/vehicles/dropdown/engines" "/api/vehicles/dropdown/trims" ) for endpoint in "${ENDPOINTS[@]}"; do RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:3001$endpoint") if [ "$RESPONSE" = "200" ]; then echo "✅ $endpoint accessible without auth" else echo "❌ $endpoint returned $RESPONSE (should be 200)" exit 1 fi done # Test CRUD endpoints require authentication echo "Testing CRUD endpoints require authentication..." CRUD_ENDPOINTS=( "/api/vehicles" "/api/vehicles/123" ) for endpoint in "${CRUD_ENDPOINTS[@]}"; do RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:3001$endpoint") if [ "$RESPONSE" = "401" ]; then echo "✅ $endpoint properly requires auth" else echo "❌ $endpoint returned $RESPONSE (should be 401)" exit 1 fi done echo "✅ All authentication tests passed" ``` --- ## Category 2: Performance Testing ### Test 2.1: Response Time Measurement **Purpose**: Verify all dropdown APIs respond in < 100ms **Test Script**: `test-performance.sh` ```bash #!/bin/bash echo "=== Performance Tests ===" ENDPOINTS=( "/api/vehicles/dropdown/makes" "/api/vehicles/dropdown/models/Honda" "/api/vehicles/dropdown/transmissions" "/api/vehicles/dropdown/engines" "/api/vehicles/dropdown/trims" ) MAX_RESPONSE_TIME=100 # milliseconds for endpoint in "${ENDPOINTS[@]}"; do echo "Testing $endpoint performance..." # Run 5 tests and get average TOTAL_TIME=0 for i in {1..5}; do START_TIME=$(date +%s%3N) curl -s "http://localhost:3001$endpoint" > /dev/null END_TIME=$(date +%s%3N) RESPONSE_TIME=$((END_TIME - START_TIME)) TOTAL_TIME=$((TOTAL_TIME + RESPONSE_TIME)) done AVG_TIME=$((TOTAL_TIME / 5)) if [ "$AVG_TIME" -lt "$MAX_RESPONSE_TIME" ]; then echo "✅ $endpoint: ${AVG_TIME}ms (under ${MAX_RESPONSE_TIME}ms)" else echo "❌ $endpoint: ${AVG_TIME}ms (exceeds ${MAX_RESPONSE_TIME}ms)" exit 1 fi done echo "✅ All performance tests passed" ``` ### Test 2.2: Cache Performance Testing **Purpose**: Verify caching improves performance on subsequent requests **Test Script**: `test-cache-performance.sh` ```bash #!/bin/bash echo "=== Cache Performance Tests ===" ENDPOINT="/api/vehicles/dropdown/makes" # Clear cache (requires Redis access) docker-compose exec redis redis-cli FLUSHDB echo "Testing first request (cache miss)..." START_TIME=$(date +%s%3N) curl -s "http://localhost:3001$ENDPOINT" > /dev/null END_TIME=$(date +%s%3N) FIRST_REQUEST_TIME=$((END_TIME - START_TIME)) echo "Testing second request (cache hit)..." START_TIME=$(date +%s%3N) curl -s "http://localhost:3001$ENDPOINT" > /dev/null END_TIME=$(date +%s%3N) SECOND_REQUEST_TIME=$((END_TIME - START_TIME)) echo "First request: ${FIRST_REQUEST_TIME}ms" echo "Second request: ${SECOND_REQUEST_TIME}ms" # Cache hit should be significantly faster if [ "$SECOND_REQUEST_TIME" -lt "$FIRST_REQUEST_TIME" ]; then IMPROVEMENT=$((((FIRST_REQUEST_TIME - SECOND_REQUEST_TIME) * 100) / FIRST_REQUEST_TIME)) echo "✅ Cache improved performance by ${IMPROVEMENT}%" else echo "❌ Cache did not improve performance" exit 1 fi echo "✅ Cache performance test passed" ``` --- ## Category 3: Data Accuracy Validation ### Test 3.1: VIN Decoding Accuracy **Purpose**: Verify VIN decoding produces accurate results **Test Script**: `test-vin-accuracy.sh` ```bash #!/bin/bash echo "=== VIN Decoding Accuracy Tests ===" # Test VINs with known results declare -A TEST_VINS=( ["1HGBH41JXMN109186"]="Honda,Civic,2021" ["3GTUUFEL6PG140748"]="GMC,Sierra,2023" ["1G1YU3D64H5602799"]="Chevrolet,Corvette,2017" ) for vin in "${!TEST_VINS[@]}"; do echo "Testing VIN: $vin" # Create test vehicle to trigger VIN decoding RESPONSE=$(curl -s -X POST "http://localhost:3001/api/vehicles" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer test-token" \ -d "{\"vin\":\"$vin\",\"nickname\":\"Test\"}" \ 2>/dev/null || echo "AUTH_ERROR") if [ "$RESPONSE" = "AUTH_ERROR" ]; then echo "⚠️ Skipping VIN test due to authentication (expected in testing)" continue fi # Parse expected results IFS=',' read -r EXPECTED_MAKE EXPECTED_MODEL EXPECTED_YEAR <<< "${TEST_VINS[$vin]}" # Extract actual results ACTUAL_MAKE=$(echo "$RESPONSE" | jq -r '.make // empty') ACTUAL_MODEL=$(echo "$RESPONSE" | jq -r '.model // empty') ACTUAL_YEAR=$(echo "$RESPONSE" | jq -r '.year // empty') # Validate results if [ "$ACTUAL_MAKE" = "$EXPECTED_MAKE" ] && \ [ "$ACTUAL_MODEL" = "$EXPECTED_MODEL" ] && \ [ "$ACTUAL_YEAR" = "$EXPECTED_YEAR" ]; then echo "✅ VIN $vin decoded correctly" else echo "❌ VIN $vin decoded incorrectly:" echo " Expected: $EXPECTED_MAKE $EXPECTED_MODEL $EXPECTED_YEAR" echo " Actual: $ACTUAL_MAKE $ACTUAL_MODEL $ACTUAL_YEAR" exit 1 fi done echo "✅ VIN accuracy tests passed" ``` ### Test 3.2: Data Completeness Check **Purpose**: Verify MVP Platform database has comprehensive data **Test Script**: `test-data-completeness.sh` ```bash #!/bin/bash echo "=== Data Completeness Tests ===" # Test makes count MAKES_COUNT=$(curl -s http://localhost:3001/api/vehicles/dropdown/makes | jq '. | length') echo "Makes available: $MAKES_COUNT" if [ "$MAKES_COUNT" -lt 50 ]; then echo "❌ Too few makes ($MAKES_COUNT < 50)" exit 1 fi # Test transmissions count TRANS_COUNT=$(curl -s http://localhost:3001/api/vehicles/dropdown/transmissions | jq '. | length') echo "Transmissions available: $TRANS_COUNT" if [ "$TRANS_COUNT" -lt 10 ]; then echo "❌ Too few transmissions ($TRANS_COUNT < 10)" exit 1 fi # Test engines count ENGINES_COUNT=$(curl -s http://localhost:3001/api/vehicles/dropdown/engines | jq '. | length') echo "Engines available: $ENGINES_COUNT" if [ "$ENGINES_COUNT" -lt 20 ]; then echo "❌ Too few engines ($ENGINES_COUNT < 20)" exit 1 fi echo "✅ Data completeness tests passed" ``` --- ## Category 4: ETL Process Testing ### Test 4.1: ETL Execution Test **Purpose**: Verify ETL process runs successfully **Test Script**: `test-etl-execution.sh` ```bash #!/bin/bash echo "=== ETL Execution Tests ===" # Check ETL container is running if ! docker-compose ps etl-scheduler | grep -q "Up"; then echo "❌ ETL scheduler container is not running" exit 1 fi # Test manual ETL execution echo "Running manual ETL test..." docker-compose exec etl-scheduler python -m etl.main test-connections if [ $? -eq 0 ]; then echo "✅ ETL connections successful" else echo "❌ ETL connections failed" exit 1 fi # Check ETL status echo "Checking ETL status..." docker-compose exec etl-scheduler /app/scripts/check-etl-status.sh if [ $? -eq 0 ]; then echo "✅ ETL status check passed" else echo "⚠️ ETL status check returned warnings (may be expected)" fi echo "✅ ETL execution tests completed" ``` ### Test 4.2: ETL Scheduling Test **Purpose**: Verify ETL is properly scheduled **Test Script**: `test-etl-scheduling.sh` ```bash #!/bin/bash echo "=== ETL Scheduling Tests ===" # Check cron job is configured CRON_OUTPUT=$(docker-compose exec etl-scheduler crontab -l) if echo "$CRON_OUTPUT" | grep -q "etl.main build-catalog"; then echo "✅ ETL cron job is configured" else echo "❌ ETL cron job not found" exit 1 fi # Check cron daemon is running if docker-compose exec etl-scheduler pgrep cron > /dev/null; then echo "✅ Cron daemon is running" else echo "❌ Cron daemon is not running" exit 1 fi echo "✅ ETL scheduling tests passed" ``` --- ## Category 5: Error Handling & Recovery ### Test 5.1: Database Connection Error Handling **Purpose**: Verify graceful handling when MVP Platform database is unavailable **Test Script**: `test-error-handling.sh` ```bash #!/bin/bash echo "=== Error Handling Tests ===" # Stop MVP Platform database temporarily echo "Stopping MVP Platform database..." docker-compose stop mvp-platform-database sleep 5 # Test API responses when database is down RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:3001/api/vehicles/dropdown/makes") if [ "$RESPONSE" = "503" ] || [ "$RESPONSE" = "500" ]; then echo "✅ API properly handles database unavailability (returned $RESPONSE)" else echo "❌ API returned unexpected status: $RESPONSE" fi # Restart database echo "Restarting MVP Platform database..." docker-compose start mvp-platform-database # Wait for database to be ready sleep 15 # Test API recovery RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:3001/api/vehicles/dropdown/makes") if [ "$RESPONSE" = "200" ]; then echo "✅ API recovered after database restart" else echo "❌ API did not recover (returned $RESPONSE)" exit 1 fi echo "✅ Error handling tests passed" ``` --- ## Category 6: Load Testing ### Test 6.1: Concurrent Request Testing **Purpose**: Verify system handles multiple concurrent requests **Test Script**: `test-load.sh` ```bash #!/bin/bash echo "=== Load Testing ===" ENDPOINT="http://localhost:3001/api/vehicles/dropdown/makes" CONCURRENT_REQUESTS=50 MAX_RESPONSE_TIME=500 # milliseconds echo "Running $CONCURRENT_REQUESTS concurrent requests..." # Create temporary file for results RESULTS_FILE=$(mktemp) # Run concurrent requests for i in $(seq 1 $CONCURRENT_REQUESTS); do { START_TIME=$(date +%s%3N) HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$ENDPOINT") END_TIME=$(date +%s%3N) RESPONSE_TIME=$((END_TIME - START_TIME)) echo "$HTTP_CODE,$RESPONSE_TIME" >> "$RESULTS_FILE" } & done # Wait for all requests to complete wait # Analyze results SUCCESS_COUNT=$(grep -c "^200," "$RESULTS_FILE") TOTAL_COUNT=$(wc -l < "$RESULTS_FILE") AVG_TIME=$(awk -F',' '{sum+=$2} END {print sum/NR}' "$RESULTS_FILE") MAX_TIME=$(awk -F',' '{max=($2>max?$2:max)} END {print max}' "$RESULTS_FILE") echo "Results:" echo " Successful requests: $SUCCESS_COUNT/$TOTAL_COUNT" echo " Average response time: ${AVG_TIME}ms" echo " Maximum response time: ${MAX_TIME}ms" # Cleanup rm "$RESULTS_FILE" # Validate results if [ "$SUCCESS_COUNT" -eq "$TOTAL_COUNT" ] && [ "$MAX_TIME" -lt "$MAX_RESPONSE_TIME" ]; then echo "✅ Load test passed" else echo "❌ Load test failed" exit 1 fi ``` --- ## Category 7: Security Validation ### Test 7.1: SQL Injection Prevention **Purpose**: Verify protection against SQL injection attacks **Test Script**: `test-security.sh` ```bash #!/bin/bash echo "=== Security Tests ===" # Test SQL injection attempts in make parameter INJECTION_ATTEMPTS=( "'; DROP TABLE vehicles; --" "' OR '1'='1" "'; SELECT * FROM users; --" "../../../etc/passwd" ) for injection in "${INJECTION_ATTEMPTS[@]}"; do echo "Testing injection attempt: $injection" # URL encode the injection ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$injection'))") RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" \ "http://localhost:3001/api/vehicles/dropdown/models/$ENCODED") # Should return 400, 404, or 500 (not 200 with injected content) if [ "$RESPONSE" != "200" ]; then echo "✅ Injection attempt blocked (returned $RESPONSE)" else echo "⚠️ Injection attempt returned 200 (investigating...)" # Additional validation would be needed here fi done echo "✅ Security tests completed" ``` --- ## Comprehensive Test Execution ### Master Test Script **Location**: `test-all.sh` ```bash #!/bin/bash echo "=========================================" echo "MotoVaultPro Vehicle ETL Integration Tests" echo "=========================================" # Set up chmod +x test-*.sh # Track test results PASSED=0 FAILED=0 run_test() { echo echo "Running $1..." if ./$1; then echo "✅ $1 PASSED" ((PASSED++)) else echo "❌ $1 FAILED" ((FAILED++)) fi } # Execute all test categories run_test "test-api-formats.sh" run_test "test-authentication.sh" run_test "test-performance.sh" run_test "test-cache-performance.sh" run_test "test-data-completeness.sh" run_test "test-etl-execution.sh" run_test "test-etl-scheduling.sh" run_test "test-error-handling.sh" run_test "test-load.sh" run_test "test-security.sh" # Final results echo echo "=========================================" echo "TEST SUMMARY" echo "=========================================" echo "Passed: $PASSED" echo "Failed: $FAILED" echo "Total: $((PASSED + FAILED))" if [ $FAILED -eq 0 ]; then echo "✅ ALL TESTS PASSED" echo "Vehicle ETL integration is ready for production!" exit 0 else echo "❌ SOME TESTS FAILED" echo "Please review failed tests before proceeding." exit 1 fi ``` ## Post-Testing Actions ### Success Actions If all tests pass: 1. **Document Test Results**: Save test output and timestamps 2. **Update Monitoring**: Configure alerts for ETL failures 3. **Schedule Production Deployment**: Plan rollout timing 4. **Update Documentation**: Mark implementation as complete ### Failure Actions If tests fail: 1. **Identify Root Cause**: Review failed test details 2. **Fix Issues**: Address specific failures 3. **Re-run Tests**: Validate fixes work 4. **Update Documentation**: Document any issues found ## Ongoing Monitoring After successful testing, implement ongoing monitoring: 1. **API Performance Monitoring**: Track response times daily 2. **ETL Success Monitoring**: Weekly ETL completion alerts 3. **Data Quality Checks**: Monthly data completeness validation 4. **Error Rate Monitoring**: Track and alert on API error rates ## Rollback Plan If critical issues are discovered during testing: 1. **Immediate Rollback**: Revert to external vPIC API 2. **Data Preservation**: Ensure no data loss occurs 3. **Service Continuity**: Maintain all existing functionality 4. **Issue Analysis**: Investigate and document problems 5. **Improved Re-implementation**: Address issues before retry