fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.
This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).
Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
739
consent-service/tests/integration_test.go
Normal file
739
consent-service/tests/integration_test.go
Normal file
@@ -0,0 +1,739 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Integration tests for the Consent Service
|
||||
// These tests simulate complete user workflows
|
||||
|
||||
func init() {
|
||||
gin.SetMode(gin.TestMode)
|
||||
}
|
||||
|
||||
// TestFullAuthFlow tests the complete authentication workflow
|
||||
func TestFullAuthFlow(t *testing.T) {
|
||||
t.Log("Starting full authentication flow integration test")
|
||||
|
||||
// Step 1: Register a new user
|
||||
t.Run("Step 1: Register User", func(t *testing.T) {
|
||||
reqBody := map[string]string{
|
||||
"email": "testuser@example.com",
|
||||
"password": "SecurePassword123!",
|
||||
"name": "Test User",
|
||||
}
|
||||
|
||||
// Validate registration data
|
||||
if reqBody["email"] == "" || reqBody["password"] == "" {
|
||||
t.Fatal("Registration data incomplete")
|
||||
}
|
||||
|
||||
// Check password strength
|
||||
if len(reqBody["password"]) < 8 {
|
||||
t.Error("Password too weak")
|
||||
}
|
||||
|
||||
t.Log("User registration data validated")
|
||||
})
|
||||
|
||||
// Step 2: Verify email
|
||||
t.Run("Step 2: Verify Email", func(t *testing.T) {
|
||||
token := "verification-token-123"
|
||||
|
||||
if token == "" {
|
||||
t.Fatal("Verification token missing")
|
||||
}
|
||||
|
||||
t.Log("Email verification simulated")
|
||||
})
|
||||
|
||||
// Step 3: Login
|
||||
t.Run("Step 3: Login", func(t *testing.T) {
|
||||
loginReq := map[string]string{
|
||||
"email": "testuser@example.com",
|
||||
"password": "SecurePassword123!",
|
||||
}
|
||||
|
||||
if loginReq["email"] == "" || loginReq["password"] == "" {
|
||||
t.Fatal("Login credentials incomplete")
|
||||
}
|
||||
|
||||
// Simulate successful login
|
||||
accessToken := "jwt-access-token-123"
|
||||
refreshToken := "jwt-refresh-token-456"
|
||||
|
||||
if accessToken == "" || refreshToken == "" {
|
||||
t.Fatal("Tokens not generated")
|
||||
}
|
||||
|
||||
t.Log("Login successful, tokens generated")
|
||||
})
|
||||
|
||||
// Step 4: Setup 2FA
|
||||
t.Run("Step 4: Setup 2FA", func(t *testing.T) {
|
||||
// Generate TOTP secret
|
||||
totpSecret := "JBSWY3DPEHPK3PXP"
|
||||
|
||||
if totpSecret == "" {
|
||||
t.Fatal("TOTP secret not generated")
|
||||
}
|
||||
|
||||
// Verify TOTP code
|
||||
totpCode := "123456"
|
||||
if len(totpCode) != 6 {
|
||||
t.Error("Invalid TOTP code format")
|
||||
}
|
||||
|
||||
t.Log("2FA setup completed")
|
||||
})
|
||||
|
||||
// Step 5: Login with 2FA
|
||||
t.Run("Step 5: Login with 2FA", func(t *testing.T) {
|
||||
// First phase - email/password
|
||||
challengeID := uuid.New().String()
|
||||
|
||||
if challengeID == "" {
|
||||
t.Fatal("Challenge ID not generated")
|
||||
}
|
||||
|
||||
// Second phase - TOTP verification
|
||||
totpCode := "654321"
|
||||
if len(totpCode) != 6 {
|
||||
t.Error("Invalid TOTP code")
|
||||
}
|
||||
|
||||
t.Log("2FA login flow completed")
|
||||
})
|
||||
|
||||
// Step 6: Refresh token
|
||||
t.Run("Step 6: Refresh Access Token", func(t *testing.T) {
|
||||
refreshToken := "jwt-refresh-token-456"
|
||||
|
||||
if refreshToken == "" {
|
||||
t.Fatal("Refresh token missing")
|
||||
}
|
||||
|
||||
// Generate new access token
|
||||
newAccessToken := "jwt-access-token-789"
|
||||
|
||||
if newAccessToken == "" {
|
||||
t.Fatal("New access token not generated")
|
||||
}
|
||||
|
||||
t.Log("Token refresh successful")
|
||||
})
|
||||
|
||||
// Step 7: Logout
|
||||
t.Run("Step 7: Logout", func(t *testing.T) {
|
||||
// Revoke tokens
|
||||
sessionRevoked := true
|
||||
|
||||
if !sessionRevoked {
|
||||
t.Error("Session not properly revoked")
|
||||
}
|
||||
|
||||
t.Log("Logout successful")
|
||||
})
|
||||
}
|
||||
|
||||
// TestDocumentLifecycle tests the complete document workflow
|
||||
func TestDocumentLifecycle(t *testing.T) {
|
||||
t.Log("Starting document lifecycle integration test")
|
||||
|
||||
var documentID uuid.UUID
|
||||
var versionID uuid.UUID
|
||||
|
||||
// Step 1: Create document (Admin)
|
||||
t.Run("Step 1: Admin Creates Document", func(t *testing.T) {
|
||||
docReq := map[string]interface{}{
|
||||
"type": "terms",
|
||||
"name": "Terms of Service",
|
||||
"description": "Our terms and conditions",
|
||||
"is_mandatory": true,
|
||||
}
|
||||
|
||||
// Validate
|
||||
if docReq["type"] == "" || docReq["name"] == "" {
|
||||
t.Fatal("Document data incomplete")
|
||||
}
|
||||
|
||||
documentID = uuid.New()
|
||||
t.Logf("Document created with ID: %s", documentID)
|
||||
})
|
||||
|
||||
// Step 2: Create version (Admin)
|
||||
t.Run("Step 2: Admin Creates Version", func(t *testing.T) {
|
||||
versionReq := map[string]interface{}{
|
||||
"document_id": documentID.String(),
|
||||
"version": "1.0.0",
|
||||
"language": "de",
|
||||
"title": "Nutzungsbedingungen",
|
||||
"content": "<h1>Terms</h1><p>Content...</p>",
|
||||
"summary": "Initial version",
|
||||
}
|
||||
|
||||
if versionReq["version"] == "" || versionReq["content"] == "" {
|
||||
t.Fatal("Version data incomplete")
|
||||
}
|
||||
|
||||
versionID = uuid.New()
|
||||
t.Logf("Version created with ID: %s", versionID)
|
||||
})
|
||||
|
||||
// Step 3: Submit for review (Admin)
|
||||
t.Run("Step 3: Submit for Review", func(t *testing.T) {
|
||||
currentStatus := "draft"
|
||||
newStatus := "review"
|
||||
|
||||
if currentStatus != "draft" {
|
||||
t.Error("Can only submit drafts for review")
|
||||
}
|
||||
|
||||
t.Logf("Status changed: %s -> %s", currentStatus, newStatus)
|
||||
})
|
||||
|
||||
// Step 4: Approve version (DSB)
|
||||
t.Run("Step 4: DSB Approves Version", func(t *testing.T) {
|
||||
approverRole := "data_protection_officer"
|
||||
currentStatus := "review"
|
||||
|
||||
if approverRole != "data_protection_officer" {
|
||||
t.Error("Only DSB can approve")
|
||||
}
|
||||
|
||||
if currentStatus != "review" {
|
||||
t.Error("Can only approve review versions")
|
||||
}
|
||||
|
||||
newStatus := "approved"
|
||||
t.Logf("Version approved, status: %s", newStatus)
|
||||
})
|
||||
|
||||
// Step 5: Publish version (Admin/DSB)
|
||||
t.Run("Step 5: Publish Version", func(t *testing.T) {
|
||||
currentStatus := "approved"
|
||||
|
||||
if currentStatus != "approved" && currentStatus != "scheduled" {
|
||||
t.Error("Can only publish approved/scheduled versions")
|
||||
}
|
||||
|
||||
publishedAt := time.Now()
|
||||
t.Logf("Version published at: %s", publishedAt)
|
||||
})
|
||||
|
||||
// Step 6: User views published document
|
||||
t.Run("Step 6: User Views Document", func(t *testing.T) {
|
||||
language := "de"
|
||||
|
||||
// Fetch latest published version
|
||||
if language == "" {
|
||||
language = "de" // default
|
||||
}
|
||||
|
||||
t.Log("User retrieved latest published version")
|
||||
})
|
||||
|
||||
// Step 7: Archive old version
|
||||
t.Run("Step 7: Archive Old Version", func(t *testing.T) {
|
||||
status := "published"
|
||||
|
||||
if status != "published" {
|
||||
t.Error("Can only archive published versions")
|
||||
}
|
||||
|
||||
newStatus := "archived"
|
||||
t.Logf("Version archived, status: %s", newStatus)
|
||||
})
|
||||
}
|
||||
|
||||
// TestConsentFlow tests the complete consent workflow
|
||||
func TestConsentFlow(t *testing.T) {
|
||||
t.Log("Starting consent flow integration test")
|
||||
|
||||
userID := uuid.New()
|
||||
versionID := uuid.New()
|
||||
|
||||
// Step 1: User checks consent status
|
||||
t.Run("Step 1: Check Consent Status", func(t *testing.T) {
|
||||
documentType := "terms"
|
||||
|
||||
hasConsent := false
|
||||
needsUpdate := true
|
||||
|
||||
if hasConsent {
|
||||
t.Log("User already has consent")
|
||||
}
|
||||
|
||||
if !needsUpdate {
|
||||
t.Error("Should need consent for new document")
|
||||
}
|
||||
|
||||
t.Logf("User %s needs consent for %s", userID, documentType)
|
||||
})
|
||||
|
||||
// Step 2: User retrieves document details
|
||||
t.Run("Step 2: Get Document Details", func(t *testing.T) {
|
||||
language := "de"
|
||||
|
||||
if language == "" {
|
||||
t.Error("Language required")
|
||||
}
|
||||
|
||||
t.Log("Document details retrieved")
|
||||
})
|
||||
|
||||
// Step 3: User gives consent
|
||||
t.Run("Step 3: Give Consent", func(t *testing.T) {
|
||||
consentReq := map[string]interface{}{
|
||||
"version_id": versionID.String(),
|
||||
"consented": true,
|
||||
}
|
||||
|
||||
if consentReq["version_id"] == "" {
|
||||
t.Fatal("Version ID required")
|
||||
}
|
||||
|
||||
consentID := uuid.New()
|
||||
consentedAt := time.Now()
|
||||
|
||||
t.Logf("Consent given, ID: %s, At: %s", consentID, consentedAt)
|
||||
})
|
||||
|
||||
// Step 4: Verify consent recorded
|
||||
t.Run("Step 4: Verify Consent", func(t *testing.T) {
|
||||
hasConsent := true
|
||||
needsUpdate := false
|
||||
|
||||
if !hasConsent {
|
||||
t.Error("Consent should be recorded")
|
||||
}
|
||||
|
||||
if needsUpdate {
|
||||
t.Error("Should not need update after consent")
|
||||
}
|
||||
|
||||
t.Log("Consent verified")
|
||||
})
|
||||
|
||||
// Step 5: New version published
|
||||
t.Run("Step 5: New Version Published", func(t *testing.T) {
|
||||
newVersionID := uuid.New()
|
||||
|
||||
// Check if consent needs update
|
||||
currentVersionID := versionID
|
||||
latestVersionID := newVersionID
|
||||
|
||||
needsUpdate := currentVersionID != latestVersionID
|
||||
|
||||
if !needsUpdate {
|
||||
t.Error("Should need update for new version")
|
||||
}
|
||||
|
||||
t.Log("New version published, consent update needed")
|
||||
})
|
||||
|
||||
// Step 6: User withdraws consent
|
||||
t.Run("Step 6: Withdraw Consent", func(t *testing.T) {
|
||||
withdrawnConsentID := uuid.New()
|
||||
|
||||
withdrawnAt := time.Now()
|
||||
consented := false
|
||||
|
||||
if consented {
|
||||
t.Error("Consent should be withdrawn")
|
||||
}
|
||||
|
||||
t.Logf("Consent %s withdrawn at: %s", withdrawnConsentID, withdrawnAt)
|
||||
})
|
||||
|
||||
// Step 7: User gives consent again
|
||||
t.Run("Step 7: Re-consent", func(t *testing.T) {
|
||||
newConsentID := uuid.New()
|
||||
consented := true
|
||||
|
||||
if !consented {
|
||||
t.Error("Should be consented")
|
||||
}
|
||||
|
||||
t.Logf("Re-consented, ID: %s", newConsentID)
|
||||
})
|
||||
|
||||
// Step 8: Get consent history
|
||||
t.Run("Step 8: View Consent History", func(t *testing.T) {
|
||||
// Fetch all consents for user
|
||||
consentCount := 2 // initial + re-consent
|
||||
|
||||
if consentCount < 1 {
|
||||
t.Error("Should have consent history")
|
||||
}
|
||||
|
||||
t.Logf("User has %d consent records", consentCount)
|
||||
})
|
||||
}
|
||||
|
||||
// TestOAuthFlow tests the OAuth 2.0 authorization code flow
|
||||
func TestOAuthFlow(t *testing.T) {
|
||||
t.Log("Starting OAuth flow integration test")
|
||||
|
||||
clientID := "client-app-123"
|
||||
_ = uuid.New() // userID simulated
|
||||
|
||||
// Step 1: Authorization request
|
||||
t.Run("Step 1: Authorization Request", func(t *testing.T) {
|
||||
authReq := map[string]string{
|
||||
"response_type": "code",
|
||||
"client_id": clientID,
|
||||
"redirect_uri": "https://app.example.com/callback",
|
||||
"scope": "read:consents write:consents",
|
||||
"state": "random-state-123",
|
||||
}
|
||||
|
||||
if authReq["response_type"] != "code" {
|
||||
t.Error("Must use authorization code flow")
|
||||
}
|
||||
|
||||
if authReq["state"] == "" {
|
||||
t.Error("State required for CSRF protection")
|
||||
}
|
||||
|
||||
t.Log("Authorization request validated")
|
||||
})
|
||||
|
||||
// Step 2: User approves
|
||||
t.Run("Step 2: User Approves", func(t *testing.T) {
|
||||
approved := true
|
||||
|
||||
if !approved {
|
||||
t.Skip("User denied authorization")
|
||||
}
|
||||
|
||||
authCode := "auth-code-abc123"
|
||||
t.Logf("Authorization code issued: %s", authCode)
|
||||
})
|
||||
|
||||
// Step 3: Exchange code for token
|
||||
t.Run("Step 3: Token Exchange", func(t *testing.T) {
|
||||
tokenReq := map[string]string{
|
||||
"grant_type": "authorization_code",
|
||||
"code": "auth-code-abc123",
|
||||
"redirect_uri": "https://app.example.com/callback",
|
||||
"client_id": clientID,
|
||||
}
|
||||
|
||||
if tokenReq["grant_type"] != "authorization_code" {
|
||||
t.Error("Invalid grant type")
|
||||
}
|
||||
|
||||
accessToken := "access-token-xyz"
|
||||
refreshToken := "refresh-token-def"
|
||||
expiresIn := 3600
|
||||
|
||||
if accessToken == "" || refreshToken == "" {
|
||||
t.Fatal("Tokens not issued")
|
||||
}
|
||||
|
||||
t.Logf("Tokens issued, expires in %d seconds", expiresIn)
|
||||
})
|
||||
|
||||
// Step 4: Use access token
|
||||
t.Run("Step 4: Access Protected Resource", func(t *testing.T) {
|
||||
accessToken := "access-token-xyz"
|
||||
|
||||
if accessToken == "" {
|
||||
t.Fatal("Access token required")
|
||||
}
|
||||
|
||||
// Make API request
|
||||
authorized := true
|
||||
|
||||
if !authorized {
|
||||
t.Error("Token should grant access")
|
||||
}
|
||||
|
||||
t.Log("Successfully accessed protected resource")
|
||||
})
|
||||
|
||||
// Step 5: Refresh token
|
||||
t.Run("Step 5: Refresh Access Token", func(t *testing.T) {
|
||||
refreshReq := map[string]string{
|
||||
"grant_type": "refresh_token",
|
||||
"refresh_token": "refresh-token-def",
|
||||
"client_id": clientID,
|
||||
}
|
||||
|
||||
if refreshReq["grant_type"] != "refresh_token" {
|
||||
t.Error("Invalid grant type")
|
||||
}
|
||||
|
||||
newAccessToken := "access-token-new"
|
||||
t.Logf("New access token issued: %s", newAccessToken)
|
||||
})
|
||||
}
|
||||
|
||||
// TestConsentDeadlineFlow tests consent deadline and suspension workflow
|
||||
func TestConsentDeadlineFlow(t *testing.T) {
|
||||
t.Log("Starting consent deadline flow test")
|
||||
|
||||
_ = uuid.New() // userID simulated
|
||||
_ = uuid.New() // versionID simulated
|
||||
|
||||
// Step 1: New mandatory version published
|
||||
t.Run("Step 1: Mandatory Version Published", func(t *testing.T) {
|
||||
isMandatory := true
|
||||
|
||||
if !isMandatory {
|
||||
t.Skip("Only for mandatory documents")
|
||||
}
|
||||
|
||||
// Create deadline
|
||||
deadlineAt := time.Now().AddDate(0, 0, 30)
|
||||
|
||||
t.Logf("Deadline created: %s (30 days)", deadlineAt)
|
||||
})
|
||||
|
||||
// Step 2: Send reminder (14 days before)
|
||||
t.Run("Step 2: First Reminder", func(t *testing.T) {
|
||||
daysLeft := 14
|
||||
urgency := "normal"
|
||||
|
||||
if daysLeft <= 7 {
|
||||
urgency = "warning"
|
||||
}
|
||||
|
||||
t.Logf("Reminder sent, %d days left, urgency: %s", daysLeft, urgency)
|
||||
})
|
||||
|
||||
// Step 3: Send urgent reminder (3 days before)
|
||||
t.Run("Step 3: Urgent Reminder", func(t *testing.T) {
|
||||
daysLeft := 3
|
||||
urgency := "urgent"
|
||||
|
||||
if daysLeft > 3 {
|
||||
t.Skip("Not yet urgent")
|
||||
}
|
||||
|
||||
t.Logf("Urgent reminder sent, urgency level: %s", urgency)
|
||||
})
|
||||
|
||||
// Step 4: Deadline passes without consent
|
||||
t.Run("Step 4: Deadline Exceeded", func(t *testing.T) {
|
||||
deadlineAt := time.Now().AddDate(0, 0, -1)
|
||||
hasConsent := false
|
||||
isOverdue := deadlineAt.Before(time.Now())
|
||||
|
||||
if !isOverdue {
|
||||
t.Skip("Not yet overdue")
|
||||
}
|
||||
|
||||
if hasConsent {
|
||||
t.Skip("User has consent")
|
||||
}
|
||||
|
||||
t.Log("Deadline exceeded without consent")
|
||||
})
|
||||
|
||||
// Step 5: Suspend account
|
||||
t.Run("Step 5: Suspend Account", func(t *testing.T) {
|
||||
accountStatus := "suspended"
|
||||
suspensionReason := "consent_deadline_exceeded"
|
||||
|
||||
if accountStatus != "suspended" {
|
||||
t.Error("Account should be suspended")
|
||||
}
|
||||
|
||||
t.Logf("Account suspended: %s", suspensionReason)
|
||||
})
|
||||
|
||||
// Step 6: User gives consent
|
||||
t.Run("Step 6: User Gives Consent", func(t *testing.T) {
|
||||
consentGiven := true
|
||||
|
||||
if !consentGiven {
|
||||
t.Error("Consent should be given")
|
||||
}
|
||||
|
||||
t.Log("Consent provided")
|
||||
})
|
||||
|
||||
// Step 7: Lift suspension
|
||||
t.Run("Step 7: Lift Suspension", func(t *testing.T) {
|
||||
accountStatus := "active"
|
||||
liftedAt := time.Now()
|
||||
|
||||
if accountStatus != "active" {
|
||||
t.Error("Account should be active")
|
||||
}
|
||||
|
||||
t.Logf("Suspension lifted at: %s", liftedAt)
|
||||
})
|
||||
}
|
||||
|
||||
// TestGDPRDataExport tests GDPR data export workflow
|
||||
func TestGDPRDataExport(t *testing.T) {
|
||||
t.Log("Starting GDPR data export test")
|
||||
|
||||
userID := uuid.New()
|
||||
|
||||
// Step 1: Request data export
|
||||
t.Run("Step 1: Request Data Export", func(t *testing.T) {
|
||||
exportID := uuid.New()
|
||||
status := "pending"
|
||||
|
||||
if status != "pending" {
|
||||
t.Error("Export should start as pending")
|
||||
}
|
||||
|
||||
t.Logf("Export requested, ID: %s", exportID)
|
||||
})
|
||||
|
||||
// Step 2: Process export
|
||||
t.Run("Step 2: Process Export", func(t *testing.T) {
|
||||
status := "processing"
|
||||
|
||||
// Collect user data
|
||||
userData := map[string]interface{}{
|
||||
"user": map[string]string{"id": userID.String(), "email": "user@example.com"},
|
||||
"consents": []interface{}{},
|
||||
"cookie_consents": []interface{}{},
|
||||
"audit_log": []interface{}{},
|
||||
}
|
||||
|
||||
if userData == nil {
|
||||
t.Fatal("User data not collected")
|
||||
}
|
||||
|
||||
t.Logf("Export %s", status)
|
||||
})
|
||||
|
||||
// Step 3: Export complete
|
||||
t.Run("Step 3: Export Complete", func(t *testing.T) {
|
||||
status := "completed"
|
||||
downloadURL := "https://example.com/exports/user-data.json"
|
||||
expiresAt := time.Now().AddDate(0, 0, 7)
|
||||
|
||||
if status != "completed" {
|
||||
t.Error("Export should be completed")
|
||||
}
|
||||
|
||||
if downloadURL == "" {
|
||||
t.Error("Download URL required")
|
||||
}
|
||||
|
||||
t.Logf("Export complete, expires at: %s", expiresAt)
|
||||
})
|
||||
|
||||
// Step 4: User downloads data
|
||||
t.Run("Step 4: Download Export", func(t *testing.T) {
|
||||
downloaded := true
|
||||
|
||||
if !downloaded {
|
||||
t.Error("Export should be downloadable")
|
||||
}
|
||||
|
||||
t.Log("Export downloaded")
|
||||
})
|
||||
}
|
||||
|
||||
// Helper functions for integration tests
|
||||
|
||||
// makeRequest simulates an HTTP request
|
||||
func makeRequest(t *testing.T, method, endpoint string, body interface{}, headers map[string]string) *httptest.ResponseRecorder {
|
||||
var req *http.Request
|
||||
|
||||
if body != nil {
|
||||
jsonBody, _ := json.Marshal(body)
|
||||
req, _ = http.NewRequest(method, endpoint, bytes.NewBuffer(jsonBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
} else {
|
||||
req, _ = http.NewRequest(method, endpoint, nil)
|
||||
}
|
||||
|
||||
// Add custom headers
|
||||
for key, value := range headers {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
return w
|
||||
}
|
||||
|
||||
// assertStatus checks HTTP status code
|
||||
func assertStatus(t *testing.T, expected, actual int) {
|
||||
if actual != expected {
|
||||
t.Errorf("Expected status %d, got %d", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
// assertJSONField checks a JSON field value
|
||||
func assertJSONField(t *testing.T, body []byte, field string, expected interface{}) {
|
||||
var response map[string]interface{}
|
||||
if err := json.Unmarshal(body, &response); err != nil {
|
||||
t.Fatalf("Failed to parse JSON: %v", err)
|
||||
}
|
||||
|
||||
actual, ok := response[field]
|
||||
if !ok {
|
||||
t.Errorf("Field %s not found in response", field)
|
||||
return
|
||||
}
|
||||
|
||||
if actual != expected {
|
||||
t.Errorf("Field %s: expected %v, got %v", field, expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
// logTestStep logs a test step with context
|
||||
func logTestStep(t *testing.T, step int, description string) {
|
||||
t.Logf("Step %d: %s", step, description)
|
||||
}
|
||||
|
||||
// TestEndToEndScenario runs a complete end-to-end scenario
|
||||
func TestEndToEndScenario(t *testing.T) {
|
||||
t.Log("Running complete end-to-end scenario")
|
||||
|
||||
scenario := []struct {
|
||||
step int
|
||||
description string
|
||||
action func(t *testing.T)
|
||||
}{
|
||||
{1, "User registers", func(t *testing.T) {
|
||||
t.Log("User registration")
|
||||
}},
|
||||
{2, "User verifies email", func(t *testing.T) {
|
||||
t.Log("Email verified")
|
||||
}},
|
||||
{3, "User logs in", func(t *testing.T) {
|
||||
t.Log("User logged in")
|
||||
}},
|
||||
{4, "User views documents", func(t *testing.T) {
|
||||
t.Log("Documents retrieved")
|
||||
}},
|
||||
{5, "User gives consent", func(t *testing.T) {
|
||||
t.Log("Consent given")
|
||||
}},
|
||||
{6, "Admin publishes new version", func(t *testing.T) {
|
||||
t.Log("New version published")
|
||||
}},
|
||||
{7, "User updates consent", func(t *testing.T) {
|
||||
t.Log("Consent updated")
|
||||
}},
|
||||
{8, "User exports data", func(t *testing.T) {
|
||||
t.Log("Data exported")
|
||||
}},
|
||||
}
|
||||
|
||||
for _, s := range scenario {
|
||||
t.Run(fmt.Sprintf("Step_%d_%s", s.step, s.description), s.action)
|
||||
}
|
||||
|
||||
t.Log("End-to-end scenario completed successfully")
|
||||
}
|
||||
Reference in New Issue
Block a user