Files
user-system/internal/auth/state_test.go
long-agent 582ad7a069 test: add comprehensive test coverage and improve code quality
- Add new test files for auth, service, and handler modules
- Improve test organization and coverage
- Refactor code for better maintainability
- Add captcha, settings, stats, and theme handler tests
- Add auth module tests (CAS, OAuth, password, SSO, state)
- Add service layer tests for auth, export, permissions, roles
- All Go tests pass (exit code 0)
- All frontend tests pass (325 tests in 59 files)
2026-04-17 20:43:50 +08:00

214 lines
4.4 KiB
Go

package auth
import (
"sync"
"testing"
"time"
)
func TestStateManager_Store(t *testing.T) {
sm := &StateManager{
states: make(map[string]time.Time),
ttl: 10 * time.Minute,
}
sm.Store("test-state")
sm.mu.RLock()
_, exists := sm.states["test-state"]
sm.mu.RUnlock()
if !exists {
t.Error("Store() did not store the state")
}
}
func TestStateManager_Validate(t *testing.T) {
sm := &StateManager{
states: make(map[string]time.Time),
ttl: 10 * time.Minute,
}
// Test validating existing state
sm.Store("valid-state")
if !sm.Validate("valid-state") {
t.Error("Validate() returned false for valid state")
}
// Test validating non-existent state
if sm.Validate("non-existent-state") {
t.Error("Validate() returned true for non-existent state")
}
}
func TestStateManager_Validate_Expired(t *testing.T) {
sm := &StateManager{
states: make(map[string]time.Time),
ttl: 1 * time.Millisecond,
}
// Store a state
sm.Store("expired-state")
// Manually set to expired
sm.mu.Lock()
sm.states["expired-state"] = time.Now().Add(-2 * time.Hour)
sm.mu.Unlock()
// Wait for ttl to pass
time.Sleep(10 * time.Millisecond)
// Should return false for expired state
if sm.Validate("expired-state") {
t.Error("Validate() should return false for expired state")
}
}
func TestStateManager_Delete(t *testing.T) {
sm := &StateManager{
states: make(map[string]time.Time),
ttl: 10 * time.Minute,
}
sm.Store("state-to-delete")
sm.Delete("state-to-delete")
sm.mu.RLock()
_, exists := sm.states["state-to-delete"]
sm.mu.RUnlock()
if exists {
t.Error("Delete() did not remove the state")
}
}
func TestStateManager_Cleanup(t *testing.T) {
sm := &StateManager{
states: make(map[string]time.Time),
ttl: 10 * time.Minute,
}
// Add some states
sm.Store("valid-state")
// Manually add expired states (stored time + ttl should be before now)
sm.mu.Lock()
sm.states["expired-state-1"] = time.Now().Add(-20 * time.Minute) // 10 min + 10 min ttl = 20 min ago expired
sm.states["expired-state-2"] = time.Now().Add(-15 * time.Minute) // 5 min after ttl expired
sm.mu.Unlock()
sm.Cleanup()
sm.mu.RLock()
defer sm.mu.RUnlock()
// Valid state should remain
if _, exists := sm.states["valid-state"]; !exists {
t.Error("Cleanup() removed valid state")
}
// Expired states should be removed
if _, exists := sm.states["expired-state-1"]; exists {
t.Error("Cleanup() did not remove expired-state-1")
}
if _, exists := sm.states["expired-state-2"]; exists {
t.Error("Cleanup() did not remove expired-state-2")
}
}
func TestStateManager_StartCleanupRoutine(t *testing.T) {
sm := &StateManager{
states: make(map[string]time.Time),
ttl: 1 * time.Millisecond,
}
stop := make(chan struct{})
sm.StartCleanupRoutine(stop)
// Add an expired state
sm.mu.Lock()
sm.states["to-cleanup"] = time.Now().Add(-1 * time.Hour)
sm.mu.Unlock()
// Wait for cleanup to run (5 minute ticker, but we'll just verify the routine started)
// We'll stop it immediately for testing
close(stop)
// Give goroutine time to exit
time.Sleep(100 * time.Millisecond)
}
func TestStartCleanupRoutineWithManager(t *testing.T) {
// Reset for test
cleanupRoutineManager = nil
// Start the routine
StartCleanupRoutineWithManager()
if cleanupRoutineManager == nil {
t.Error("StartCleanupRoutineWithManager() did not initialize manager")
}
// Starting again should be no-op
StartCleanupRoutineWithManager()
// Stop the routine
StopCleanupRoutine()
if cleanupRoutineManager != nil {
t.Error("StopCleanupRoutine() did not clean up manager")
}
}
func TestStopCleanupRoutine_NilManager(t *testing.T) {
// Ensure manager is nil
cleanupRoutineManager = nil
// Should not panic
StopCleanupRoutine()
}
func TestGetStateManager(t *testing.T) {
sm := GetStateManager()
if sm == nil {
t.Error("GetStateManager() returned nil")
}
// Should return same instance
sm2 := GetStateManager()
if sm != sm2 {
t.Error("GetStateManager() should return same instance")
}
}
func TestStateManager_ConcurrentAccess(t *testing.T) {
sm := &StateManager{
states: make(map[string]time.Time),
ttl: 10 * time.Minute,
}
var wg sync.WaitGroup
numOps := 100
// Concurrent stores
for i := 0; i < numOps; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
sm.Store(string(rune(i)))
}(i)
}
// Concurrent validates
for i := 0; i < numOps; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
sm.Validate(string(rune(i)))
}(i)
}
wg.Wait()
}