#!/bin/bash # ============================================================================== # AURGANIZE V6.2 - API TESTING SCRIPT # ============================================================================== # Purpose: Comprehensive testing of all API endpoints # Usage: ./test-api.sh # Requires: curl, jq (for JSON parsing) # ============================================================================== set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # API Base URL BASE_URL="http://localhost:8080/api/v1" # Test data TEST_EMAIL="test-$(date +%s)@example.com" # Unique email with timestamp TEST_PASSWORD="Test123!@#" TEST_FIRST_NAME="Test" TEST_LAST_NAME="User" TEST_TENANT_NAME="Test Company $(date +%s)" # Variables to store tokens ACCESS_TOKEN="" REFRESH_TOKEN="" USER_ID="" TENANT_ID="" echo "==========================================" echo "AURGANIZE V6.2 API TESTING" echo "==========================================" echo "" echo "Base URL: $BASE_URL" echo "Test Email: $TEST_EMAIL" echo "" # ============================================================================== # Helper Functions # ============================================================================== # Function to print test header print_test() { echo "" echo -e "${BLUE}==========================================" echo "TEST: $1" echo -e "==========================================${NC}" echo "" } # Function to print success print_success() { echo -e "${GREEN}✅ $1${NC}" } # Function to print error print_error() { echo -e "${RED}❌ $1${NC}" } # Function to print warning print_warning() { echo -e "${YELLOW}⚠️ $1${NC}" } # Function to check if jq is installed check_jq() { if ! command -v jq &> /dev/null; then print_warning "jq is not installed (JSON parsing will be limited)" echo " Install: apt-get install jq or brew install jq" return 1 fi return 0 } # Check for jq HAS_JQ=false if check_jq; then HAS_JQ=true fi # ============================================================================== # TEST 1: Health Check (Unprotected) # ============================================================================== print_test "1. Health Check (Unprotected Route)" echo "Request: GET /health" RESPONSE=$(curl -s -w "\n%{http_code}" http://localhost:8080/health) HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | head -n-1) echo "HTTP Status: $HTTP_CODE" echo "Response Body:" echo "$BODY" | jq '.' 2>/dev/null || echo "$BODY" if [ "$HTTP_CODE" = "200" ]; then print_success "Health check passed" else print_error "Health check failed (expected 200, got $HTTP_CODE)" exit 1 fi # ============================================================================== # TEST 2: User Registration # ============================================================================== print_test "2. User Registration" echo "Creating new user account..." echo " Email: $TEST_EMAIL" echo " Password: $TEST_PASSWORD" echo " Name: $TEST_FIRST_NAME $TEST_LAST_NAME" echo " Tenant: $TEST_TENANT_NAME" echo "" REGISTER_PAYLOAD=$(cat </dev/null || echo "$REGISTER_PAYLOAD" echo "" RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$BASE_URL/auth/register" \ -H "Content-Type: application/json" \ -d "$REGISTER_PAYLOAD") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | head -n-1) echo "HTTP Status: $HTTP_CODE" echo "Response Body:" echo "$BODY" | jq '.' 2>/dev/null || echo "$BODY" if [ "$HTTP_CODE" = "201" ]; then print_success "User registered successfully" # Extract tokens and IDs if [ "$HAS_JQ" = true ]; then ACCESS_TOKEN=$(echo "$BODY" | jq -r '.access_token') REFRESH_TOKEN=$(echo "$BODY" | jq -r '.refresh_token') USER_ID=$(echo "$BODY" | jq -r '.user.id') TENANT_ID=$(echo "$BODY" | jq -r '.tenant.id') echo "" echo "Extracted data:" echo " User ID: $USER_ID" echo " Tenant ID: $TENANT_ID" echo " Access Token: ${ACCESS_TOKEN:0:30}..." echo " Refresh Token: ${REFRESH_TOKEN:0:30}..." else print_warning "Install jq to extract tokens automatically" echo "Manually extract access_token and refresh_token from response above" fi else print_error "Registration failed (expected 201, got $HTTP_CODE)" echo "" echo "Common issues:" echo " 1. Validator not registered (check main.go line 128)" echo " 2. Database user doesn't exist" echo " 3. Transaction interface mismatch" exit 1 fi # ============================================================================== # TEST 3: Duplicate Registration (Should Fail) # ============================================================================== print_test "3. Duplicate Registration (Should Fail with 409)" echo "Attempting to register same email again..." RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$BASE_URL/auth/register" \ -H "Content-Type: application/json" \ -d "$REGISTER_PAYLOAD") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | head -n-1) echo "HTTP Status: $HTTP_CODE" echo "Response Body:" echo "$BODY" | jq '.' 2>/dev/null || echo "$BODY" if [ "$HTTP_CODE" = "409" ]; then print_success "Correctly rejected duplicate email" else print_warning "Expected 409 Conflict, got $HTTP_CODE (check uniqueness constraint)" fi # ============================================================================== # TEST 4: Invalid Registration (Weak Password) # ============================================================================== print_test "4. Invalid Registration - Weak Password" WEAK_PASSWORD_PAYLOAD=$(cat </dev/null || echo "$BODY" if [ "$HTTP_CODE" = "400" ]; then print_success "Correctly rejected weak password" else print_warning "Expected 400 Bad Request, got $HTTP_CODE (check validator)" fi # ============================================================================== # TEST 5: Rate Limiting (Registration) # ============================================================================== print_test "5. Rate Limiting on Registration (5 requests/minute)" echo "Sending 6 rapid registration requests..." echo "(Rate limit: 5 requests/minute)" echo "" RATE_LIMITED=false for i in {1..6}; do UNIQUE_EMAIL="ratelimit-$i-$(date +%s)@example.com" RATE_LIMIT_PAYLOAD=$(cat </dev/null || echo "$BODY" if [ "$HTTP_CODE" = "200" ]; then print_success "Login successful" # Update tokens (login gives new tokens) if [ "$HAS_JQ" = true ]; then ACCESS_TOKEN=$(echo "$BODY" | jq -r '.access_token') REFRESH_TOKEN=$(echo "$BODY" | jq -r '.refresh_token') echo "" echo "New tokens received:" echo " Access Token: ${ACCESS_TOKEN:0:30}..." echo " Refresh Token: ${REFRESH_TOKEN:0:30}..." fi else print_error "Login failed (expected 200, got $HTTP_CODE)" exit 1 fi # ============================================================================== # TEST 7: Login with Wrong Password # ============================================================================== print_test "7. Login with Wrong Password (Should Fail)" WRONG_PASSWORD_PAYLOAD=$(cat </dev/null || echo "$BODY" if [ "$HTTP_CODE" = "401" ]; then print_success "Correctly rejected invalid credentials" else print_warning "Expected 401 Unauthorized, got $HTTP_CODE" fi # ============================================================================== # TEST 8: Protected Route (Health with Auth) # ============================================================================== print_test "8. Protected Health Endpoint" if [ -z "$ACCESS_TOKEN" ]; then print_error "No access token available (login may have failed)" exit 1 fi echo "Request: GET /api/v1/health" echo "Authorization: Bearer ${ACCESS_TOKEN:0:30}..." echo "" RESPONSE=$(curl -s -w "\n%{http_code}" "$BASE_URL/health" \ -H "Authorization: Bearer $ACCESS_TOKEN") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | head -n-1) echo "HTTP Status: $HTTP_CODE" echo "Response Body:" echo "$BODY" | jq '.' 2>/dev/null || echo "$BODY" if [ "$HTTP_CODE" = "200" ]; then print_success "Authentication middleware working" else print_error "Protected route failed (expected 200, got $HTTP_CODE)" fi # ============================================================================== # TEST 9: Protected Route WITHOUT Token (Should Fail) # ============================================================================== print_test "9. Protected Route Without Token (Should Fail)" echo "Request: GET /api/v1/health" echo "Authorization: (none)" echo "" RESPONSE=$(curl -s -w "\n%{http_code}" "$BASE_URL/health") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | head -n-1) echo "HTTP Status: $HTTP_CODE" echo "Response Body:" echo "$BODY" | jq '.' 2>/dev/null || echo "$BODY" if [ "$HTTP_CODE" = "401" ]; then print_success "Correctly rejected request without token" else print_warning "Expected 401 Unauthorized, got $HTTP_CODE" fi # ============================================================================== # TEST 10: Get My Tenant # ============================================================================== print_test "10. Get My Tenant (Row-Level Security Test)" echo "Request: GET /api/v1/tenants/mine" echo "This tests:" echo " - Authentication middleware" echo " - Row-Level Security (RLS)" echo " - Tenant context extraction" echo "" RESPONSE=$(curl -s -w "\n%{http_code}" "$BASE_URL/tenants/mine" \ -H "Authorization: Bearer $ACCESS_TOKEN") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | head -n-1) echo "HTTP Status: $HTTP_CODE" echo "Response Body:" echo "$BODY" | jq '.' 2>/dev/null || echo "$BODY" if [ "$HTTP_CODE" = "200" ]; then print_success "Tenant retrieval successful (RLS working)" if [ "$HAS_JQ" = true ]; then RETRIEVED_TENANT_ID=$(echo "$BODY" | jq -r '.id') TENANT_NAME=$(echo "$BODY" | jq -r '.name') echo "" echo "Tenant details:" echo " ID: $RETRIEVED_TENANT_ID" echo " Name: $TENANT_NAME" if [ "$RETRIEVED_TENANT_ID" = "$TENANT_ID" ]; then print_success "Tenant ID matches registration" else print_warning "Tenant ID mismatch!" fi fi else print_error "Get tenant failed (expected 200, got $HTTP_CODE)" fi # ============================================================================== # TEST 11: Get Specific Tenant by ID # ============================================================================== print_test "11. Get Specific Tenant by ID" if [ -z "$TENANT_ID" ]; then print_warning "Skipping: No tenant ID available" else echo "Request: GET /api/v1/tenants/$TENANT_ID" echo "" RESPONSE=$(curl -s -w "\n%{http_code}" "$BASE_URL/tenants/$TENANT_ID" \ -H "Authorization: Bearer $ACCESS_TOKEN") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | head -n-1) echo "HTTP Status: $HTTP_CODE" echo "Response Body:" echo "$BODY" | jq '.' 2>/dev/null || echo "$BODY" if [ "$HTTP_CODE" = "200" ]; then print_success "Specific tenant retrieval working" else print_error "Get specific tenant failed (expected 200, got $HTTP_CODE)" echo "" echo "This might fail if route order is wrong:" echo " /tenants/mine must come BEFORE /tenants/:id" echo " Otherwise ':id' matches 'mine' as a UUID" fi fi # ============================================================================== # TEST 12: Token Refresh # ============================================================================== print_test "12. Token Refresh (Token Rotation)" if [ -z "$REFRESH_TOKEN" ]; then print_error "No refresh token available" exit 1 fi echo "Request: POST /api/v1/auth/refresh" echo "Using refresh token: ${REFRESH_TOKEN:0:30}..." echo "" echo "This tests:" echo " - Refresh token validation" echo " - Token rotation (new access + refresh tokens)" echo " - Session management" echo "" RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$BASE_URL/auth/refresh" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $REFRESH_TOKEN") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | head -n-1) echo "HTTP Status: $HTTP_CODE" echo "Response Body:" echo "$BODY" | jq '.' 2>/dev/null || echo "$BODY" if [ "$HTTP_CODE" = "200" ]; then print_success "Token refresh successful" if [ "$HAS_JQ" = true ]; then NEW_ACCESS_TOKEN=$(echo "$BODY" | jq -r '.access_token') NEW_REFRESH_TOKEN=$(echo "$BODY" | jq -r '.refresh_token') echo "" echo "New tokens received:" echo " Access Token: ${NEW_ACCESS_TOKEN:0:30}..." echo " Refresh Token: ${NEW_REFRESH_TOKEN:0:30}..." # Verify tokens are different (rotation) if [ "$NEW_ACCESS_TOKEN" != "$ACCESS_TOKEN" ]; then print_success "Access token rotated (security best practice)" else print_warning "Access token not rotated" fi if [ "$NEW_REFRESH_TOKEN" != "$REFRESH_TOKEN" ]; then print_success "Refresh token rotated (security best practice)" else print_warning "Refresh token not rotated" fi # Update tokens for logout test ACCESS_TOKEN="$NEW_ACCESS_TOKEN" REFRESH_TOKEN="$NEW_REFRESH_TOKEN" fi else print_error "Token refresh failed (expected 200, got $HTTP_CODE)" fi # ============================================================================== # TEST 13: Use Old Refresh Token (Should Fail) # ============================================================================== print_test "13. Use Old Refresh Token After Rotation (Should Fail)" echo "After token rotation, old refresh token should be invalid..." echo "" # We'd need to save the old token before refresh to test this properly print_warning "Skipping: Requires saving old token before rotation" echo "Manual test: Try using old refresh token after successful refresh" # ============================================================================== # TEST 14: User Logout # ============================================================================== print_test "14. User Logout (Session Revocation)" echo "Request: POST /api/v1/auth/logout" echo "This should:" echo " - Revoke current refresh token" echo " - Mark session as revoked" echo " - Old refresh token should no longer work" echo "" RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$BASE_URL/auth/logout" \ -H "Authorization: Bearer $ACCESS_TOKEN") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | head -n-1) echo "HTTP Status: $HTTP_CODE" echo "Response Body:" echo "$BODY" | jq '.' 2>/dev/null || echo "$BODY" if [ "$HTTP_CODE" = "200" ]; then print_success "Logout successful" else print_warning "Logout returned $HTTP_CODE (expected 200)" fi # ============================================================================== # TEST 15: Use Tokens After Logout (Should Fail) # ============================================================================== print_test "15. Use Tokens After Logout (Should Fail)" echo "Attempting to refresh token after logout..." RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$BASE_URL/auth/refresh" \ -H "Authorization: Bearer $REFRESH_TOKEN") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | head -n-1) echo "HTTP Status: $HTTP_CODE" echo "Response Body:" echo "$BODY" | jq '.' 2>/dev/null || echo "$BODY" if [ "$HTTP_CODE" = "401" ]; then print_success "Refresh token correctly revoked after logout" else print_warning "Expected 401, got $HTTP_CODE (session may not be revoked)" fi # ============================================================================== # FINAL SUMMARY # ============================================================================== echo "" echo "==========================================" echo "TEST SUMMARY" echo "==========================================" echo "" print_success "All critical tests completed!" echo "" echo "Tested functionality:" echo " ✅ Health check (public route)" echo " ✅ User registration with transaction" echo " ✅ Duplicate email detection" echo " ✅ Password validation" echo " ✅ Rate limiting" echo " ✅ User login" echo " ✅ Invalid credential handling" echo " ✅ Authentication middleware" echo " ✅ Row-Level Security (RLS)" echo " ✅ Tenant context management" echo " ✅ Token refresh & rotation" echo " ✅ Session revocation (logout)" echo "" echo "Database verification:" echo " Check sessions table:" echo " docker exec -it aurganize-postgres psql -U postgres -d aurganize_dev -c \"SELECT id, user_id, is_revoked, device_type, created_at FROM sessions;\"" echo "" echo " Check users table:" echo " docker exec -it aurganize-postgres psql -U postgres -d aurganize_dev -c \"SELECT id, email, role, created_at FROM users;\"" echo "" echo " Check tenants table:" echo " docker exec -it aurganize-postgres psql -U postgres -d aurganize_dev -c \"SELECT id, name, type, created_at FROM tenants;\"" echo "" echo "==========================================" echo "TESTING COMPLETE" echo "=========================================="