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:
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