This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/consent-service/internal/services/auth_service_test.go
Benjamin Admin 21a844cb8a 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>
2026-02-09 09:51:32 +01:00

368 lines
8.5 KiB
Go

package services
import (
"testing"
"time"
"github.com/breakpilot/consent-service/internal/models"
"github.com/google/uuid"
)
// TestHashPassword tests password hashing
func TestHashPassword(t *testing.T) {
// Create service without DB for unit tests
s := &AuthService{}
password := "testPassword123!"
hash, err := s.HashPassword(password)
if err != nil {
t.Fatalf("HashPassword failed: %v", err)
}
if hash == "" {
t.Error("Hash should not be empty")
}
if hash == password {
t.Error("Hash should not equal the original password")
}
// Hash should be different each time (bcrypt uses random salt)
hash2, _ := s.HashPassword(password)
if hash == hash2 {
t.Error("Same password should produce different hashes due to salt")
}
}
// TestVerifyPassword tests password verification
func TestVerifyPassword(t *testing.T) {
s := &AuthService{}
password := "testPassword123!"
hash, _ := s.HashPassword(password)
// Should verify correct password
if !s.VerifyPassword(password, hash) {
t.Error("VerifyPassword should return true for correct password")
}
// Should reject incorrect password
if s.VerifyPassword("wrongPassword", hash) {
t.Error("VerifyPassword should return false for incorrect password")
}
// Should reject empty password
if s.VerifyPassword("", hash) {
t.Error("VerifyPassword should return false for empty password")
}
}
// TestGenerateSecureToken tests token generation
func TestGenerateSecureToken(t *testing.T) {
s := &AuthService{}
tests := []struct {
name string
length int
}{
{"short token", 16},
{"standard token", 32},
{"long token", 64},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
token, err := s.GenerateSecureToken(tt.length)
if err != nil {
t.Fatalf("GenerateSecureToken failed: %v", err)
}
if token == "" {
t.Error("Token should not be empty")
}
// Tokens should be unique
token2, _ := s.GenerateSecureToken(tt.length)
if token == token2 {
t.Error("Generated tokens should be unique")
}
})
}
}
// TestHashToken tests token hashing for storage
func TestHashToken(t *testing.T) {
s := &AuthService{}
token := "test-token-123"
hash := s.HashToken(token)
if hash == "" {
t.Error("Hash should not be empty")
}
if hash == token {
t.Error("Hash should not equal the original token")
}
// Same token should produce same hash (deterministic)
hash2 := s.HashToken(token)
if hash != hash2 {
t.Error("Same token should produce same hash")
}
// Different tokens should produce different hashes
differentHash := s.HashToken("different-token")
if hash == differentHash {
t.Error("Different tokens should produce different hashes")
}
}
// TestGenerateAccessToken tests JWT access token generation
func TestGenerateAccessToken(t *testing.T) {
s := &AuthService{
jwtSecret: "test-secret-key-for-testing-purposes",
accessTokenExp: time.Hour,
}
user := &models.User{
ID: uuid.New(),
Email: "test@example.com",
Role: "user",
AccountStatus: "active",
}
token, err := s.GenerateAccessToken(user)
if err != nil {
t.Fatalf("GenerateAccessToken failed: %v", err)
}
if token == "" {
t.Error("Token should not be empty")
}
// Token should have three parts (header.payload.signature)
parts := 0
for _, c := range token {
if c == '.' {
parts++
}
}
if parts != 2 {
t.Errorf("JWT token should have 3 parts, got %d dots", parts)
}
}
// TestValidateAccessToken tests JWT token validation
func TestValidateAccessToken(t *testing.T) {
secret := "test-secret-key-for-testing-purposes"
s := &AuthService{
jwtSecret: secret,
accessTokenExp: time.Hour,
}
user := &models.User{
ID: uuid.New(),
Email: "test@example.com",
Role: "admin",
AccountStatus: "active",
}
token, _ := s.GenerateAccessToken(user)
// Should validate valid token
claims, err := s.ValidateAccessToken(token)
if err != nil {
t.Fatalf("ValidateAccessToken failed: %v", err)
}
if claims.UserID != user.ID.String() {
t.Errorf("Expected UserID %s, got %s", user.ID.String(), claims.UserID)
}
if claims.Email != user.Email {
t.Errorf("Expected Email %s, got %s", user.Email, claims.Email)
}
if claims.Role != user.Role {
t.Errorf("Expected Role %s, got %s", user.Role, claims.Role)
}
}
// TestValidateAccessToken_Invalid tests invalid token scenarios
func TestValidateAccessToken_Invalid(t *testing.T) {
s := &AuthService{
jwtSecret: "test-secret-key-for-testing-purposes",
accessTokenExp: time.Hour,
}
tests := []struct {
name string
token string
}{
{"empty token", ""},
{"invalid format", "not-a-jwt-token"},
{"invalid signature", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiMTIzIn0.invalidsignature"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := s.ValidateAccessToken(tt.token)
if err == nil {
t.Error("ValidateAccessToken should fail for invalid token")
}
})
}
}
// TestValidateAccessToken_WrongSecret tests token with wrong secret
func TestValidateAccessToken_WrongSecret(t *testing.T) {
s1 := &AuthService{
jwtSecret: "secret-one",
accessTokenExp: time.Hour,
}
s2 := &AuthService{
jwtSecret: "secret-two",
accessTokenExp: time.Hour,
}
user := &models.User{
ID: uuid.New(),
Email: "test@example.com",
Role: "user",
AccountStatus: "active",
}
// Generate token with first secret
token, _ := s1.GenerateAccessToken(user)
// Try to validate with second secret (should fail)
_, err := s2.ValidateAccessToken(token)
if err == nil {
t.Error("ValidateAccessToken should fail when using wrong secret")
}
}
// TestGenerateRefreshToken tests refresh token generation
func TestGenerateRefreshToken(t *testing.T) {
s := &AuthService{}
token, hash, err := s.GenerateRefreshToken()
if err != nil {
t.Fatalf("GenerateRefreshToken failed: %v", err)
}
if token == "" {
t.Error("Token should not be empty")
}
if hash == "" {
t.Error("Hash should not be empty")
}
// Verify hash matches token
expectedHash := s.HashToken(token)
if hash != expectedHash {
t.Error("Returned hash should match hashed token")
}
// Tokens should be unique
token2, hash2, _ := s.GenerateRefreshToken()
if token == token2 {
t.Error("Generated tokens should be unique")
}
if hash == hash2 {
t.Error("Generated hashes should be unique")
}
}
// TestPasswordStrength tests various password scenarios
func TestPasswordStrength(t *testing.T) {
s := &AuthService{}
passwords := []struct {
password string
valid bool
}{
{"short", true}, // bcrypt accepts any length
{"12345678", true}, // numbers only
{"password", true}, // letters only
{"Pass123!", true}, // mixed
{"", true}, // empty (bcrypt allows)
{string(make([]byte, 72)), true}, // max bcrypt length
}
for _, p := range passwords {
hash, err := s.HashPassword(p.password)
if p.valid && err != nil {
t.Errorf("HashPassword failed for valid password %q: %v", p.password, err)
}
if p.valid && !s.VerifyPassword(p.password, hash) {
t.Errorf("VerifyPassword failed for password %q", p.password)
}
}
}
// BenchmarkHashPassword benchmarks password hashing
func BenchmarkHashPassword(b *testing.B) {
s := &AuthService{}
password := "testPassword123!"
for i := 0; i < b.N; i++ {
s.HashPassword(password)
}
}
// BenchmarkVerifyPassword benchmarks password verification
func BenchmarkVerifyPassword(b *testing.B) {
s := &AuthService{}
password := "testPassword123!"
hash, _ := s.HashPassword(password)
for i := 0; i < b.N; i++ {
s.VerifyPassword(password, hash)
}
}
// BenchmarkGenerateAccessToken benchmarks JWT token generation
func BenchmarkGenerateAccessToken(b *testing.B) {
s := &AuthService{
jwtSecret: "test-secret-key-for-testing-purposes",
accessTokenExp: time.Hour,
}
user := &models.User{
ID: uuid.New(),
Email: "test@example.com",
Role: "user",
AccountStatus: "active",
}
for i := 0; i < b.N; i++ {
s.GenerateAccessToken(user)
}
}
// BenchmarkValidateAccessToken benchmarks JWT token validation
func BenchmarkValidateAccessToken(b *testing.B) {
s := &AuthService{
jwtSecret: "test-secret-key-for-testing-purposes",
accessTokenExp: time.Hour,
}
user := &models.User{
ID: uuid.New(),
Email: "test@example.com",
Role: "user",
AccountStatus: "active",
}
token, _ := s.GenerateAccessToken(user)
for i := 0; i < b.N; i++ {
s.ValidateAccessToken(token)
}
}