Files
ColaFlow/colaflow-api/comprehensive-day5-tests.ps1
Yaojia Wang 4183b10b39
Some checks failed
Code Coverage / Generate Coverage Report (push) Has been cancelled
Tests / Run Tests (9.0.x) (push) Has been cancelled
Tests / Docker Build Test (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Commit all scripts
2025-11-03 17:19:20 +01:00

487 lines
20 KiB
PowerShell

# 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
}