feat: BreakPilot PWA - Full codebase (clean push without large binaries)
Some checks failed
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
ci/woodpecker/manual/build-ci-image Pipeline was successful
ci/woodpecker/manual/main Pipeline failed
Some checks failed
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
ci/woodpecker/manual/build-ci-image Pipeline was successful
ci/woodpecker/manual/main Pipeline failed
All services: admin-v2, studio-v2, website, ai-compliance-sdk, consent-service, klausur-service, voice-service, and infrastructure. Large PDFs and compiled binaries excluded via .gitignore.
This commit is contained in:
518
consent-service/internal/services/consent_service_test.go
Normal file
518
consent-service/internal/services/consent_service_test.go
Normal file
@@ -0,0 +1,518 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// TestConsentService_CreateConsent tests creating a new consent
|
||||
func TestConsentService_CreateConsent(t *testing.T) {
|
||||
// This is a unit test with table-driven approach
|
||||
tests := []struct {
|
||||
name string
|
||||
userID uuid.UUID
|
||||
versionID uuid.UUID
|
||||
consented bool
|
||||
expectError bool
|
||||
errorContains string
|
||||
}{
|
||||
{
|
||||
name: "valid consent - accepted",
|
||||
userID: uuid.New(),
|
||||
versionID: uuid.New(),
|
||||
consented: true,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "valid consent - declined",
|
||||
userID: uuid.New(),
|
||||
versionID: uuid.New(),
|
||||
consented: false,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "empty user ID",
|
||||
userID: uuid.Nil,
|
||||
versionID: uuid.New(),
|
||||
consented: true,
|
||||
expectError: true,
|
||||
errorContains: "user ID",
|
||||
},
|
||||
{
|
||||
name: "empty version ID",
|
||||
userID: uuid.New(),
|
||||
versionID: uuid.Nil,
|
||||
consented: true,
|
||||
expectError: true,
|
||||
errorContains: "version ID",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Validate inputs (in real implementation this would be in the service)
|
||||
var hasError bool
|
||||
if tt.userID == uuid.Nil {
|
||||
hasError = true
|
||||
} else if tt.versionID == uuid.Nil {
|
||||
hasError = true
|
||||
}
|
||||
|
||||
// Assert
|
||||
if tt.expectError && !hasError {
|
||||
t.Errorf("Expected error containing '%s', got nil", tt.errorContains)
|
||||
}
|
||||
if !tt.expectError && hasError {
|
||||
t.Error("Expected no error, got error")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestConsentService_WithdrawConsent tests withdrawing consent
|
||||
func TestConsentService_WithdrawConsent(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
consentID uuid.UUID
|
||||
userID uuid.UUID
|
||||
expectError bool
|
||||
errorContains string
|
||||
}{
|
||||
{
|
||||
name: "valid withdrawal",
|
||||
consentID: uuid.New(),
|
||||
userID: uuid.New(),
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "empty consent ID",
|
||||
consentID: uuid.Nil,
|
||||
userID: uuid.New(),
|
||||
expectError: true,
|
||||
errorContains: "consent ID",
|
||||
},
|
||||
{
|
||||
name: "empty user ID",
|
||||
consentID: uuid.New(),
|
||||
userID: uuid.Nil,
|
||||
expectError: true,
|
||||
errorContains: "user ID",
|
||||
},
|
||||
{
|
||||
name: "both empty",
|
||||
consentID: uuid.Nil,
|
||||
userID: uuid.Nil,
|
||||
expectError: true,
|
||||
errorContains: "ID",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Validate
|
||||
var hasError bool
|
||||
if tt.consentID == uuid.Nil || tt.userID == uuid.Nil {
|
||||
hasError = true
|
||||
}
|
||||
|
||||
// Assert
|
||||
if tt.expectError && !hasError {
|
||||
t.Errorf("Expected error containing '%s', got nil", tt.errorContains)
|
||||
}
|
||||
if !tt.expectError && hasError {
|
||||
t.Error("Expected no error, got error")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestConsentService_CheckConsent tests checking consent status
|
||||
func TestConsentService_CheckConsent(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
userID uuid.UUID
|
||||
documentType string
|
||||
language string
|
||||
hasConsent bool
|
||||
needsUpdate bool
|
||||
expectedConsent bool
|
||||
expectedNeedsUpd bool
|
||||
}{
|
||||
{
|
||||
name: "user has current consent",
|
||||
userID: uuid.New(),
|
||||
documentType: "terms",
|
||||
language: "de",
|
||||
hasConsent: true,
|
||||
needsUpdate: false,
|
||||
expectedConsent: true,
|
||||
expectedNeedsUpd: false,
|
||||
},
|
||||
{
|
||||
name: "user has outdated consent",
|
||||
userID: uuid.New(),
|
||||
documentType: "privacy",
|
||||
language: "de",
|
||||
hasConsent: true,
|
||||
needsUpdate: true,
|
||||
expectedConsent: true,
|
||||
expectedNeedsUpd: true,
|
||||
},
|
||||
{
|
||||
name: "user has no consent",
|
||||
userID: uuid.New(),
|
||||
documentType: "cookies",
|
||||
language: "de",
|
||||
hasConsent: false,
|
||||
needsUpdate: true,
|
||||
expectedConsent: false,
|
||||
expectedNeedsUpd: true,
|
||||
},
|
||||
{
|
||||
name: "english language",
|
||||
userID: uuid.New(),
|
||||
documentType: "terms",
|
||||
language: "en",
|
||||
hasConsent: true,
|
||||
needsUpdate: false,
|
||||
expectedConsent: true,
|
||||
expectedNeedsUpd: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Simulate consent check logic
|
||||
hasConsent := tt.hasConsent
|
||||
needsUpdate := tt.needsUpdate
|
||||
|
||||
// Assert
|
||||
if hasConsent != tt.expectedConsent {
|
||||
t.Errorf("Expected hasConsent=%v, got %v", tt.expectedConsent, hasConsent)
|
||||
}
|
||||
if needsUpdate != tt.expectedNeedsUpd {
|
||||
t.Errorf("Expected needsUpdate=%v, got %v", tt.expectedNeedsUpd, needsUpdate)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestConsentService_GetConsentHistory tests retrieving consent history
|
||||
func TestConsentService_GetConsentHistory(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
userID uuid.UUID
|
||||
expectError bool
|
||||
expectEmpty bool
|
||||
}{
|
||||
{
|
||||
name: "valid user with consents",
|
||||
userID: uuid.New(),
|
||||
expectError: false,
|
||||
expectEmpty: false,
|
||||
},
|
||||
{
|
||||
name: "valid user without consents",
|
||||
userID: uuid.New(),
|
||||
expectError: false,
|
||||
expectEmpty: true,
|
||||
},
|
||||
{
|
||||
name: "invalid user ID",
|
||||
userID: uuid.Nil,
|
||||
expectError: true,
|
||||
expectEmpty: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Validate
|
||||
var err error
|
||||
if tt.userID == uuid.Nil {
|
||||
err = &ValidationError{Field: "user ID", Message: "required"}
|
||||
}
|
||||
|
||||
// Assert error expectation
|
||||
if tt.expectError && err == nil {
|
||||
t.Error("Expected error, got nil")
|
||||
}
|
||||
if !tt.expectError && err != nil {
|
||||
t.Errorf("Expected no error, got %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestConsentService_UpdateConsent tests updating existing consent
|
||||
func TestConsentService_UpdateConsent(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
consentID uuid.UUID
|
||||
userID uuid.UUID
|
||||
newConsented bool
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "update to consented",
|
||||
consentID: uuid.New(),
|
||||
userID: uuid.New(),
|
||||
newConsented: true,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "update to not consented",
|
||||
consentID: uuid.New(),
|
||||
userID: uuid.New(),
|
||||
newConsented: false,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "invalid consent ID",
|
||||
consentID: uuid.Nil,
|
||||
userID: uuid.New(),
|
||||
newConsented: true,
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var err error
|
||||
if tt.consentID == uuid.Nil {
|
||||
err = &ValidationError{Field: "consent ID", Message: "required"}
|
||||
}
|
||||
|
||||
if tt.expectError && err == nil {
|
||||
t.Error("Expected error, got nil")
|
||||
}
|
||||
if !tt.expectError && err != nil {
|
||||
t.Errorf("Expected no error, got %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestConsentService_GetConsentStats tests getting consent statistics
|
||||
func TestConsentService_GetConsentStats(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
documentType string
|
||||
totalUsers int
|
||||
consentedUsers int
|
||||
expectedRate float64
|
||||
}{
|
||||
{
|
||||
name: "100% consent rate",
|
||||
documentType: "terms",
|
||||
totalUsers: 100,
|
||||
consentedUsers: 100,
|
||||
expectedRate: 100.0,
|
||||
},
|
||||
{
|
||||
name: "50% consent rate",
|
||||
documentType: "privacy",
|
||||
totalUsers: 100,
|
||||
consentedUsers: 50,
|
||||
expectedRate: 50.0,
|
||||
},
|
||||
{
|
||||
name: "0% consent rate",
|
||||
documentType: "cookies",
|
||||
totalUsers: 100,
|
||||
consentedUsers: 0,
|
||||
expectedRate: 0.0,
|
||||
},
|
||||
{
|
||||
name: "no users",
|
||||
documentType: "terms",
|
||||
totalUsers: 0,
|
||||
consentedUsers: 0,
|
||||
expectedRate: 0.0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Calculate consent rate
|
||||
var consentRate float64
|
||||
if tt.totalUsers > 0 {
|
||||
consentRate = float64(tt.consentedUsers) / float64(tt.totalUsers) * 100
|
||||
}
|
||||
|
||||
// Assert
|
||||
if consentRate != tt.expectedRate {
|
||||
t.Errorf("Expected consent rate %.2f%%, got %.2f%%", tt.expectedRate, consentRate)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestConsentService_BulkConsentCheck tests checking multiple consents at once
|
||||
func TestConsentService_BulkConsentCheck(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
userID uuid.UUID
|
||||
documentTypes []string
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "check multiple documents",
|
||||
userID: uuid.New(),
|
||||
documentTypes: []string{"terms", "privacy", "cookies"},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "check single document",
|
||||
userID: uuid.New(),
|
||||
documentTypes: []string{"terms"},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "empty document list",
|
||||
userID: uuid.New(),
|
||||
documentTypes: []string{},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "invalid user ID",
|
||||
userID: uuid.Nil,
|
||||
documentTypes: []string{"terms"},
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var err error
|
||||
if tt.userID == uuid.Nil {
|
||||
err = &ValidationError{Field: "user ID", Message: "required"}
|
||||
}
|
||||
|
||||
if tt.expectError && err == nil {
|
||||
t.Error("Expected error, got nil")
|
||||
}
|
||||
if !tt.expectError && err != nil {
|
||||
t.Errorf("Expected no error, got %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestConsentService_ConsentVersionComparison tests version comparison logic
|
||||
func TestConsentService_ConsentVersionComparison(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
currentVersion string
|
||||
consentedVersion string
|
||||
needsUpdate bool
|
||||
}{
|
||||
{
|
||||
name: "same version",
|
||||
currentVersion: "1.0.0",
|
||||
consentedVersion: "1.0.0",
|
||||
needsUpdate: false,
|
||||
},
|
||||
{
|
||||
name: "minor version update",
|
||||
currentVersion: "1.1.0",
|
||||
consentedVersion: "1.0.0",
|
||||
needsUpdate: true,
|
||||
},
|
||||
{
|
||||
name: "major version update",
|
||||
currentVersion: "2.0.0",
|
||||
consentedVersion: "1.0.0",
|
||||
needsUpdate: true,
|
||||
},
|
||||
{
|
||||
name: "patch version update",
|
||||
currentVersion: "1.0.1",
|
||||
consentedVersion: "1.0.0",
|
||||
needsUpdate: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Simple version comparison (in real implementation use proper semver)
|
||||
needsUpdate := tt.currentVersion != tt.consentedVersion
|
||||
|
||||
if needsUpdate != tt.needsUpdate {
|
||||
t.Errorf("Expected needsUpdate=%v, got %v", tt.needsUpdate, needsUpdate)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestConsentService_ConsentDeadlineCheck tests deadline validation
|
||||
func TestConsentService_ConsentDeadlineCheck(t *testing.T) {
|
||||
now := time.Now()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
deadline time.Time
|
||||
isOverdue bool
|
||||
daysLeft int
|
||||
}{
|
||||
{
|
||||
name: "deadline in 30 days",
|
||||
deadline: now.AddDate(0, 0, 30),
|
||||
isOverdue: false,
|
||||
daysLeft: 30,
|
||||
},
|
||||
{
|
||||
name: "deadline in 7 days",
|
||||
deadline: now.AddDate(0, 0, 7),
|
||||
isOverdue: false,
|
||||
daysLeft: 7,
|
||||
},
|
||||
{
|
||||
name: "deadline today",
|
||||
deadline: now,
|
||||
isOverdue: false,
|
||||
daysLeft: 0,
|
||||
},
|
||||
{
|
||||
name: "deadline 1 day overdue",
|
||||
deadline: now.AddDate(0, 0, -1),
|
||||
isOverdue: true,
|
||||
daysLeft: -1,
|
||||
},
|
||||
{
|
||||
name: "deadline 30 days overdue",
|
||||
deadline: now.AddDate(0, 0, -30),
|
||||
isOverdue: true,
|
||||
daysLeft: -30,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Calculate if overdue
|
||||
isOverdue := tt.deadline.Before(now)
|
||||
daysLeft := int(tt.deadline.Sub(now).Hours() / 24)
|
||||
|
||||
if isOverdue != tt.isOverdue {
|
||||
t.Errorf("Expected isOverdue=%v, got %v", tt.isOverdue, isOverdue)
|
||||
}
|
||||
|
||||
// Allow 1 day difference due to time precision
|
||||
if abs(daysLeft-tt.daysLeft) > 1 {
|
||||
t.Errorf("Expected daysLeft=%d, got %d", tt.daysLeft, daysLeft)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
|
||||
// abs returns the absolute value of an integer
|
||||
func abs(n int) int {
|
||||
if n < 0 {
|
||||
return -n
|
||||
}
|
||||
return n
|
||||
}
|
||||
Reference in New Issue
Block a user