# ColaFlow Day 5 Comprehensive Integration Test Suite # Tests: Refresh Token + RBAC Implementation $baseUrl = "http://localhost:5167" $ErrorActionPreference = "Continue" # Test Results Tracking $testResults = @{ Total = 0 Passed = 0 Failed = 0 Errors = @() } function Write-TestHeader { param($TestName) Write-Host "`n========================================" -ForegroundColor Cyan Write-Host "$TestName" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan $testResults.Total++ } function Write-TestSuccess { param($Message) Write-Host "✅ $Message" -ForegroundColor Green $testResults.Passed++ } function Write-TestFailure { param($Message, $Error) Write-Host "❌ $Message" -ForegroundColor Red Write-Host " Error: $Error" -ForegroundColor DarkRed $testResults.Failed++ $testResults.Errors += @{Message=$Message; Error=$Error} } function Write-TestInfo { param($Message) Write-Host " $Message" -ForegroundColor Gray } # Wait for API to start Write-Host "Waiting for API server to start..." -ForegroundColor Yellow Start-Sleep -Seconds 5 # Check if API is running try { $healthCheck = Invoke-RestMethod -Uri "$baseUrl/api/auth/me" -Method Get 2>&1 } catch { Write-Host "Waiting additional time for API startup..." -ForegroundColor Yellow Start-Sleep -Seconds 5 } Write-Host "`n╔════════════════════════════════════════════════════════╗" -ForegroundColor Magenta Write-Host "║ ColaFlow Day 5 Integration Test Suite ║" -ForegroundColor Magenta Write-Host "║ Testing: Refresh Token + RBAC ║" -ForegroundColor Magenta Write-Host "╚════════════════════════════════════════════════════════╝" -ForegroundColor Magenta # ============================================================================ # Phase 1: Refresh Token Tests # ============================================================================ Write-Host "`n┌────────────────────────────────────────┐" -ForegroundColor Yellow Write-Host "│ PHASE 1: REFRESH TOKEN TESTS │" -ForegroundColor Yellow Write-Host "└────────────────────────────────────────┘" -ForegroundColor Yellow # Test 1: Register Tenant - Get Access & Refresh Token Write-TestHeader "Test 1: Register Tenant (Get Tokens)" $tenantSlug = "test-$(Get-Random -Minimum 1000 -Maximum 9999)" $registerBody = @{ tenantName = "Test Corp Day 5" tenantSlug = $tenantSlug subscriptionPlan = "Professional" adminEmail = "admin@testday5.com" adminPassword = "Admin@1234" adminFullName = "Test Admin" } | ConvertTo-Json try { $registerResponse = Invoke-RestMethod -Uri "$baseUrl/api/tenants/register" ` -Method Post -ContentType "application/json" -Body $registerBody $accessToken1 = $registerResponse.accessToken $refreshToken1 = $registerResponse.refreshToken $tenantId = $registerResponse.tenant.id if ($accessToken1 -and $refreshToken1) { Write-TestSuccess "Tenant registered with access token and refresh token" Write-TestInfo "Tenant ID: $tenantId" Write-TestInfo "Access Token Length: $($accessToken1.Length)" Write-TestInfo "Refresh Token Length: $($refreshToken1.Length)" } else { Write-TestFailure "Registration did not return both tokens" "Missing tokens" } } catch { Write-TestFailure "Tenant registration failed" $_.Exception.Message Write-Host "`nCRITICAL: Cannot proceed without successful registration. Exiting." -ForegroundColor Red exit 1 } # Test 2: Use Access Token to Access Protected Endpoint Write-TestHeader "Test 2: Access Protected Endpoint with Access Token" try { $headers = @{ "Authorization" = "Bearer $accessToken1" } $meResponse1 = Invoke-RestMethod -Uri "$baseUrl/api/auth/me" -Method Get -Headers $headers if ($meResponse1.userId -and $meResponse1.email) { Write-TestSuccess "Access token works for protected endpoint" Write-TestInfo "User ID: $($meResponse1.userId)" Write-TestInfo "Email: $($meResponse1.email)" } else { Write-TestFailure "Protected endpoint did not return expected data" "Missing user data" } } catch { Write-TestFailure "Failed to access protected endpoint" $_.Exception.Message } # Test 3: Refresh Access Token Write-TestHeader "Test 3: Refresh Access Token (Token Rotation)" try { $refreshBody = @{ refreshToken = $refreshToken1 } | ConvertTo-Json $refreshResponse1 = Invoke-RestMethod -Uri "$baseUrl/api/auth/refresh" ` -Method Post -ContentType "application/json" -Body $refreshBody $accessToken2 = $refreshResponse1.accessToken $refreshToken2 = $refreshResponse1.refreshToken if ($accessToken2 -and $refreshToken2 -and $accessToken2 -ne $accessToken1 -and $refreshToken2 -ne $refreshToken1) { Write-TestSuccess "Token refresh successful (new tokens generated)" Write-TestInfo "New Access Token: $($accessToken2.Substring(0, 20))..." Write-TestInfo "New Refresh Token: $($refreshToken2.Substring(0, 20))..." } else { Write-TestFailure "Token refresh failed or did not rotate tokens" "Token rotation failed" } } catch { Write-TestFailure "Token refresh request failed" $_.Exception.Message } # Test 4: Try Using Old Refresh Token (Should Fail - Token Reuse Detection) Write-TestHeader "Test 4: Token Reuse Detection (Security Test)" try { $oldRefreshBody = @{ refreshToken = $refreshToken1 } | ConvertTo-Json try { $shouldFail = Invoke-RestMethod -Uri "$baseUrl/api/auth/refresh" ` -Method Post -ContentType "application/json" -Body $oldRefreshBody Write-TestFailure "Old refresh token was accepted (security vulnerability!)" "Token reuse not detected" } catch { $statusCode = $_.Exception.Response.StatusCode.value__ if ($statusCode -eq 401) { Write-TestSuccess "Old refresh token correctly rejected (401 Unauthorized)" Write-TestInfo "Token reuse detection working correctly" } else { Write-TestFailure "Unexpected status code: $statusCode" "Expected 401" } } } catch { Write-TestFailure "Token reuse detection test failed" $_.Exception.Message } # Test 5: Use New Access Token Write-TestHeader "Test 5: New Access Token Works" try { $headers2 = @{ "Authorization" = "Bearer $accessToken2" } $meResponse2 = Invoke-RestMethod -Uri "$baseUrl/api/auth/me" -Method Get -Headers $headers2 if ($meResponse2.userId -eq $meResponse1.userId) { Write-TestSuccess "New access token works for same user" Write-TestInfo "User ID matches: $($meResponse2.userId)" } else { Write-TestFailure "New access token returned different user" "User ID mismatch" } } catch { Write-TestFailure "New access token failed" $_.Exception.Message } # Test 6: Logout (Revoke Refresh Token) Write-TestHeader "Test 6: Logout (Revoke Refresh Token)" try { $logoutBody = @{ refreshToken = $refreshToken2 } | ConvertTo-Json $logoutResponse = Invoke-RestMethod -Uri "$baseUrl/api/auth/logout" ` -Method Post -ContentType "application/json" -Body $logoutBody if ($logoutResponse.message -like "*success*") { Write-TestSuccess "Logout successful" Write-TestInfo $logoutResponse.message } else { Write-TestFailure "Logout did not return success message" $logoutResponse } } catch { Write-TestFailure "Logout request failed" $_.Exception.Message } # Test 7: Try Using Revoked Token (Should Fail) Write-TestHeader "Test 7: Revoked Token Cannot Be Used" try { $revokedRefreshBody = @{ refreshToken = $refreshToken2 } | ConvertTo-Json try { $shouldFail2 = Invoke-RestMethod -Uri "$baseUrl/api/auth/refresh" ` -Method Post -ContentType "application/json" -Body $revokedRefreshBody Write-TestFailure "Revoked token was accepted (security issue!)" "Revoked token still works" } catch { $statusCode = $_.Exception.Response.StatusCode.value__ if ($statusCode -eq 401) { Write-TestSuccess "Revoked token correctly rejected (401)" } else { Write-TestFailure "Unexpected status code: $statusCode" "Expected 401" } } } catch { Write-TestFailure "Revoked token test failed" $_.Exception.Message } # ============================================================================ # Phase 2: RBAC Tests # ============================================================================ Write-Host "`n┌────────────────────────────────────────┐" -ForegroundColor Yellow Write-Host "│ PHASE 2: RBAC TESTS │" -ForegroundColor Yellow Write-Host "└────────────────────────────────────────┘" -ForegroundColor Yellow # Test 8: Register New Tenant for RBAC Testing Write-TestHeader "Test 8: Register Tenant (RBAC Test)" $tenantSlug2 = "rbac-$(Get-Random -Minimum 1000 -Maximum 9999)" $registerBody2 = @{ tenantName = "RBAC Test Corp" tenantSlug = $tenantSlug2 subscriptionPlan = "Professional" adminEmail = "rbac@test.com" adminPassword = "Admin@1234" adminFullName = "RBAC Admin" } | ConvertTo-Json try { $registerResponse2 = Invoke-RestMethod -Uri "$baseUrl/api/tenants/register" ` -Method Post -ContentType "application/json" -Body $registerBody2 $rbacAccessToken = $registerResponse2.accessToken $rbacRefreshToken = $registerResponse2.refreshToken Write-TestSuccess "RBAC test tenant registered" Write-TestInfo "Tenant Slug: $tenantSlug2" } catch { Write-TestFailure "RBAC tenant registration failed" $_.Exception.Message } # Test 9: Verify TenantOwner Role in JWT Write-TestHeader "Test 9: Verify TenantOwner Role Assignment" try { $rbacHeaders = @{ "Authorization" = "Bearer $rbacAccessToken" } $rbacMe = Invoke-RestMethod -Uri "$baseUrl/api/auth/me" -Method Get -Headers $rbacHeaders if ($rbacMe.tenantRole -eq "TenantOwner" -and $rbacMe.role -eq "TenantOwner") { Write-TestSuccess "TenantOwner role correctly assigned" Write-TestInfo "Tenant Role: $($rbacMe.tenantRole)" Write-TestInfo "Standard Role: $($rbacMe.role)" } else { Write-TestFailure "Expected TenantOwner role" "Got: tenant_role=$($rbacMe.tenantRole), role=$($rbacMe.role)" } } catch { Write-TestFailure "Failed to verify role assignment" $_.Exception.Message } # Test 10: Login and Verify Role Persistence Write-TestHeader "Test 10: Role Persistence Across Login" try { $loginBody = @{ tenantSlug = $tenantSlug2 email = "rbac@test.com" password = "Admin@1234" } | ConvertTo-Json $loginResponse = Invoke-RestMethod -Uri "$baseUrl/api/auth/login" ` -Method Post -ContentType "application/json" -Body $loginBody $loginAccessToken = $loginResponse.accessToken $loginHeaders = @{ "Authorization" = "Bearer $loginAccessToken" } $loginMe = Invoke-RestMethod -Uri "$baseUrl/api/auth/me" -Method Get -Headers $loginHeaders if ($loginMe.tenantRole -eq "TenantOwner") { Write-TestSuccess "Role persisted after login" Write-TestInfo "Role after login: $($loginMe.tenantRole)" } else { Write-TestFailure "Role not persisted after login" "Got: $($loginMe.tenantRole)" } } catch { Write-TestFailure "Login role persistence test failed" $_.Exception.Message } # Test 11: Refresh Token Preserves Role Write-TestHeader "Test 11: Role Preserved in Refreshed Token" try { $refreshBody3 = @{ refreshToken = $rbacRefreshToken } | ConvertTo-Json $refreshResponse3 = Invoke-RestMethod -Uri "$baseUrl/api/auth/refresh" ` -Method Post -ContentType "application/json" -Body $refreshBody3 $refreshedAccessToken = $refreshResponse3.accessToken $refreshedHeaders = @{ "Authorization" = "Bearer $refreshedAccessToken" } $refreshedMe = Invoke-RestMethod -Uri "$baseUrl/api/auth/me" -Method Get -Headers $refreshedHeaders if ($refreshedMe.tenantRole -eq "TenantOwner") { Write-TestSuccess "Role preserved in refreshed token" Write-TestInfo "Role after refresh: $($refreshedMe.tenantRole)" } else { Write-TestFailure "Role not preserved in refreshed token" "Got: $($refreshedMe.tenantRole)" } } catch { Write-TestFailure "Refreshed token role test failed" $_.Exception.Message } # Test 12: JWT Claims Inspection Write-TestHeader "Test 12: Inspect JWT Claims" try { $rbacHeaders = @{ "Authorization" = "Bearer $rbacAccessToken" } $claimsResponse = Invoke-RestMethod -Uri "$baseUrl/api/auth/me" -Method Get -Headers $rbacHeaders $hasUserId = $claimsResponse.userId -ne $null $hasEmail = $claimsResponse.email -ne $null $hasTenantRole = $claimsResponse.tenantRole -ne $null $hasRole = $claimsResponse.role -ne $null $hasTenantId = $claimsResponse.tenantId -ne $null if ($hasUserId -and $hasEmail -and $hasTenantRole -and $hasRole -and $hasTenantId) { Write-TestSuccess "All required JWT claims present" Write-TestInfo "Claims: user_id, email, tenant_role, role, tenant_id" } else { Write-TestFailure "Missing JWT claims" "userId=$hasUserId, email=$hasEmail, tenantRole=$hasTenantRole, role=$hasRole, tenantId=$hasTenantId" } } catch { Write-TestFailure "JWT claims inspection failed" $_.Exception.Message } # ============================================================================ # Phase 3: Regression Tests (Day 4 Functionality) # ============================================================================ Write-Host "`n┌────────────────────────────────────────┐" -ForegroundColor Yellow Write-Host "│ PHASE 3: REGRESSION TESTS │" -ForegroundColor Yellow Write-Host "└────────────────────────────────────────┘" -ForegroundColor Yellow # Test 13: Password Hashing Still Works Write-TestHeader "Test 13: Password Hashing (Regression)" try { $testSlug = "hash-test-$(Get-Random -Minimum 1000 -Maximum 9999)" $hashTestBody = @{ tenantName = "Hash Test" tenantSlug = $testSlug subscriptionPlan = "Free" adminEmail = "hash@test.com" adminPassword = "Password@123" adminFullName = "Hash Tester" } | ConvertTo-Json $hashResponse = Invoke-RestMethod -Uri "$baseUrl/api/tenants/register" ` -Method Post -ContentType "application/json" -Body $hashTestBody # Try login with correct password $loginHashBody = @{ tenantSlug = $testSlug email = "hash@test.com" password = "Password@123" } | ConvertTo-Json $loginHashResponse = Invoke-RestMethod -Uri "$baseUrl/api/auth/login" ` -Method Post -ContentType "application/json" -Body $loginHashBody if ($loginHashResponse.accessToken) { Write-TestSuccess "Password hashing and verification working" } else { Write-TestFailure "Password hashing regression detected" "Login failed" } } catch { Write-TestFailure "Password hashing test failed" $_.Exception.Message } # Test 14: JWT Still Works Write-TestHeader "Test 14: JWT Authentication (Regression)" try { $headers = @{ "Authorization" = "Bearer $accessToken1" } $regMeResponse = Invoke-RestMethod -Uri "$baseUrl/api/auth/me" -Method Get -Headers $headers 2>&1 # Access token1 might be revoked due to token family revocation # Use a fresh token instead $headers = @{ "Authorization" = "Bearer $rbacAccessToken" } $regMeResponse = Invoke-RestMethod -Uri "$baseUrl/api/auth/me" -Method Get -Headers $headers if ($regMeResponse.userId) { Write-TestSuccess "JWT authentication still working (Day 4 regression test passed)" } else { Write-TestFailure "JWT authentication regression" "No user data returned" } } catch { Write-TestFailure "JWT regression test failed" $_.Exception.Message } # ============================================================================ # Test Summary # ============================================================================ Write-Host "`n╔════════════════════════════════════════════════════════╗" -ForegroundColor Magenta Write-Host "║ TEST EXECUTION SUMMARY ║" -ForegroundColor Magenta Write-Host "╚════════════════════════════════════════════════════════╝" -ForegroundColor Magenta Write-Host "`nTotal Tests: $($testResults.Total)" -ForegroundColor White Write-Host "Passed: $($testResults.Passed)" -ForegroundColor Green Write-Host "Failed: $($testResults.Failed)" -ForegroundColor $(if ($testResults.Failed -eq 0) { "Green" } else { "Red" }) $passRate = [math]::Round(($testResults.Passed / $testResults.Total) * 100, 2) Write-Host "Pass Rate: $passRate%" -ForegroundColor $(if ($passRate -ge 90) { "Green" } elseif ($passRate -ge 70) { "Yellow" } else { "Red" }) if ($testResults.Failed -gt 0) { Write-Host "`n❌ FAILED TESTS:" -ForegroundColor Red foreach ($error in $testResults.Errors) { Write-Host " - $($error.Message)" -ForegroundColor Red Write-Host " $($error.Error)" -ForegroundColor DarkRed } } Write-Host "`n┌────────────────────────────────────────┐" -ForegroundColor Cyan Write-Host "│ FEATURE COVERAGE │" -ForegroundColor Cyan Write-Host "└────────────────────────────────────────┘" -ForegroundColor Cyan Write-Host "Phase 1 - Refresh Token:" Write-Host " ✓ Token generation (register/login)" Write-Host " ✓ Token refresh and rotation" Write-Host " ✓ Token reuse detection" Write-Host " ✓ Token revocation (logout)" Write-Host " ✓ Security validation" Write-Host "`nPhase 2 - RBAC:" Write-Host " ✓ Role assignment (TenantOwner)" Write-Host " ✓ JWT role claims" Write-Host " ✓ Role persistence (login)" Write-Host " ✓ Role preservation (refresh)" Write-Host " ✓ Claims inspection" Write-Host "`nPhase 3 - Regression:" Write-Host " ✓ Password hashing (Day 4)" Write-Host " ✓ JWT authentication (Day 4)" Write-Host "`n╔════════════════════════════════════════════════════════╗" -ForegroundColor Magenta Write-Host "║ QUALITY ASSESSMENT ║" -ForegroundColor Magenta Write-Host "╚════════════════════════════════════════════════════════╝" -ForegroundColor Magenta if ($passRate -ge 95) { Write-Host "`n✅ EXCELLENT - All tests passed. Ready for production!" -ForegroundColor Green exit 0 } elseif ($passRate -ge 80) { Write-Host "`n⚠️ GOOD - Minor issues found. Review failed tests." -ForegroundColor Yellow exit 1 } else { Write-Host "`n❌ CRITICAL - Major issues found. DO NOT DEPLOY!" -ForegroundColor Red exit 1 }