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>
740 lines
17 KiB
Go
740 lines
17 KiB
Go
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")
|
|
}
|