add step list for server creation
All checks were successful
Release and Deploy / build (push) Successful in 9m5s
Release and Deploy / deploy (push) Successful in 26s

This commit is contained in:
Fran Jurmanović
2025-09-18 22:24:51 +02:00
parent 901dbe697e
commit 4004d83411
80 changed files with 950 additions and 2554 deletions

View File

@@ -12,30 +12,24 @@ import (
)
func TestJWT_GenerateAndValidateToken(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
jwtHandler := jwt.NewJWTHandler(os.Getenv("JWT_SECRET"))
// Create test user
user := &model.User{
ID: uuid.New(),
Username: "testuser",
RoleID: uuid.New(),
}
// Test JWT generation
token, err := jwtHandler.GenerateToken(user.ID.String())
tests.AssertNoError(t, err)
tests.AssertNotNil(t, token)
// Verify token is not empty
if token == "" {
t.Fatal("Expected non-empty token, got empty string")
}
// Test JWT validation
claims, err := jwtHandler.ValidateToken(token)
tests.AssertNoError(t, err)
tests.AssertNotNil(t, claims)
@@ -43,80 +37,66 @@ func TestJWT_GenerateAndValidateToken(t *testing.T) {
}
func TestJWT_ValidateToken_InvalidToken(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
jwtHandler := jwt.NewJWTHandler(os.Getenv("JWT_SECRET"))
// Test with invalid token
claims, err := jwtHandler.ValidateToken("invalid-token")
if err == nil {
t.Fatal("Expected error for invalid token, got nil")
}
// Direct nil check to avoid the interface wrapping issue
if claims != nil {
t.Fatalf("Expected nil claims, got %v", claims)
}
}
func TestJWT_ValidateToken_EmptyToken(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
jwtHandler := jwt.NewJWTHandler(os.Getenv("JWT_SECRET"))
// Test with empty token
claims, err := jwtHandler.ValidateToken("")
if err == nil {
t.Fatal("Expected error for empty token, got nil")
}
// Direct nil check to avoid the interface wrapping issue
if claims != nil {
t.Fatalf("Expected nil claims, got %v", claims)
}
}
func TestUser_VerifyPassword_Success(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Create test user
user := &model.User{
ID: uuid.New(),
Username: "testuser",
RoleID: uuid.New(),
}
// Hash password manually (simulating what BeforeCreate would do)
plainPassword := "password123"
hashedPassword, err := password.HashPassword(plainPassword)
tests.AssertNoError(t, err)
user.Password = hashedPassword
// Test password verification - should succeed
err = user.VerifyPassword(plainPassword)
tests.AssertNoError(t, err)
}
func TestUser_VerifyPassword_Failure(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Create test user
user := &model.User{
ID: uuid.New(),
Username: "testuser",
RoleID: uuid.New(),
}
// Hash password manually
hashedPassword, err := password.HashPassword("correct_password")
tests.AssertNoError(t, err)
user.Password = hashedPassword
// Test password verification with wrong password - should fail
err = user.VerifyPassword("wrong_password")
if err == nil {
t.Fatal("Expected error for wrong password, got nil")
@@ -124,11 +104,9 @@ func TestUser_VerifyPassword_Failure(t *testing.T) {
}
func TestUser_Validate_Success(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Create valid user
user := &model.User{
ID: uuid.New(),
Username: "testuser",
@@ -136,25 +114,21 @@ func TestUser_Validate_Success(t *testing.T) {
RoleID: uuid.New(),
}
// Test validation - should succeed
err := user.Validate()
tests.AssertNoError(t, err)
}
func TestUser_Validate_MissingUsername(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Create user without username
user := &model.User{
ID: uuid.New(),
Username: "", // Missing username
Username: "",
Password: "password123",
RoleID: uuid.New(),
}
// Test validation - should fail
err := user.Validate()
if err == nil {
t.Fatal("Expected error for missing username, got nil")
@@ -162,19 +136,16 @@ func TestUser_Validate_MissingUsername(t *testing.T) {
}
func TestUser_Validate_MissingPassword(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Create user without password
user := &model.User{
ID: uuid.New(),
Username: "testuser",
Password: "", // Missing password
Password: "",
RoleID: uuid.New(),
}
// Test validation - should fail
err := user.Validate()
if err == nil {
t.Fatal("Expected error for missing password, got nil")
@@ -182,24 +153,19 @@ func TestUser_Validate_MissingPassword(t *testing.T) {
}
func TestPassword_HashAndVerify(t *testing.T) {
// Test password hashing and verification directly
plainPassword := "test_password_123"
// Hash password
hashedPassword, err := password.HashPassword(plainPassword)
tests.AssertNoError(t, err)
tests.AssertNotNil(t, hashedPassword)
// Verify hashed password is not the same as plain password
if hashedPassword == plainPassword {
t.Fatal("Hashed password should not equal plain password")
}
// Verify correct password
err = password.VerifyPassword(hashedPassword, plainPassword)
tests.AssertNoError(t, err)
// Verify wrong password fails
err = password.VerifyPassword(hashedPassword, "wrong_password")
if err == nil {
t.Fatal("Expected error for wrong password, got nil")
@@ -215,7 +181,7 @@ func TestPassword_ValidatePasswordStrength(t *testing.T) {
{"Valid password", "StrongPassword123!", false},
{"Too short", "123", true},
{"Empty password", "", true},
{"Medium password", "password123", false}, // Depends on validation rules
{"Medium password", "password123", false},
}
for _, tc := range testCases {
@@ -235,7 +201,6 @@ func TestPassword_ValidatePasswordStrength(t *testing.T) {
}
func TestRole_Model(t *testing.T) {
// Test Role model structure
permissions := []model.Permission{
{ID: uuid.New(), Name: "read"},
{ID: uuid.New(), Name: "write"},
@@ -248,7 +213,6 @@ func TestRole_Model(t *testing.T) {
Permissions: permissions,
}
// Verify role structure
tests.AssertEqual(t, "Test Role", role.Name)
tests.AssertEqual(t, 3, len(role.Permissions))
tests.AssertEqual(t, "read", role.Permissions[0].Name)
@@ -257,19 +221,16 @@ func TestRole_Model(t *testing.T) {
}
func TestPermission_Model(t *testing.T) {
// Test Permission model structure
permission := &model.Permission{
ID: uuid.New(),
Name: "test_permission",
}
// Verify permission structure
tests.AssertEqual(t, "test_permission", permission.Name)
tests.AssertNotNil(t, permission.ID)
}
func TestUser_WithRole_Model(t *testing.T) {
// Test User model with Role relationship
permissions := []model.Permission{
{ID: uuid.New(), Name: "read"},
{ID: uuid.New(), Name: "write"},
@@ -289,7 +250,6 @@ func TestUser_WithRole_Model(t *testing.T) {
Role: role,
}
// Verify user-role relationship
tests.AssertEqual(t, "testuser", user.Username)
tests.AssertEqual(t, role.ID, user.RoleID)
tests.AssertEqual(t, "User", user.Role.Name)

View File

@@ -11,28 +11,22 @@ import (
)
func TestInMemoryCache_Set_Get_Success(t *testing.T) {
// Setup
c := cache.NewInMemoryCache()
// Test data
key := "test-key"
value := "test-value"
duration := 5 * time.Minute
// Set value in cache
c.Set(key, value, duration)
// Get value from cache
result, found := c.Get(key)
tests.AssertEqual(t, true, found)
tests.AssertEqual(t, value, result)
}
func TestInMemoryCache_Get_NotFound(t *testing.T) {
// Setup
c := cache.NewInMemoryCache()
// Try to get non-existent key
result, found := c.Get("non-existent-key")
tests.AssertEqual(t, false, found)
if result != nil {
@@ -41,43 +35,33 @@ func TestInMemoryCache_Get_NotFound(t *testing.T) {
}
func TestInMemoryCache_Set_Get_NoExpiration(t *testing.T) {
// Setup
c := cache.NewInMemoryCache()
// Test data
key := "test-key"
value := "test-value"
// Set value without expiration (duration = 0)
c.Set(key, value, 0)
// Get value from cache
result, found := c.Get(key)
tests.AssertEqual(t, true, found)
tests.AssertEqual(t, value, result)
}
func TestInMemoryCache_Expiration(t *testing.T) {
// Setup
c := cache.NewInMemoryCache()
// Test data
key := "test-key"
value := "test-value"
duration := 1 * time.Millisecond // Very short duration
duration := 1 * time.Millisecond
// Set value in cache
c.Set(key, value, duration)
// Verify it's initially there
result, found := c.Get(key)
tests.AssertEqual(t, true, found)
tests.AssertEqual(t, value, result)
// Wait for expiration
time.Sleep(2 * time.Millisecond)
// Try to get expired value
result, found = c.Get(key)
tests.AssertEqual(t, false, found)
if result != nil {
@@ -86,26 +70,20 @@ func TestInMemoryCache_Expiration(t *testing.T) {
}
func TestInMemoryCache_Delete(t *testing.T) {
// Setup
c := cache.NewInMemoryCache()
// Test data
key := "test-key"
value := "test-value"
duration := 5 * time.Minute
// Set value in cache
c.Set(key, value, duration)
// Verify it's there
result, found := c.Get(key)
tests.AssertEqual(t, true, found)
tests.AssertEqual(t, value, result)
// Delete the key
c.Delete(key)
// Verify it's gone
result, found = c.Get(key)
tests.AssertEqual(t, false, found)
if result != nil {
@@ -114,37 +92,29 @@ func TestInMemoryCache_Delete(t *testing.T) {
}
func TestInMemoryCache_Overwrite(t *testing.T) {
// Setup
c := cache.NewInMemoryCache()
// Test data
key := "test-key"
value1 := "test-value-1"
value2 := "test-value-2"
duration := 5 * time.Minute
// Set first value
c.Set(key, value1, duration)
// Verify first value
result, found := c.Get(key)
tests.AssertEqual(t, true, found)
tests.AssertEqual(t, value1, result)
// Overwrite with second value
c.Set(key, value2, duration)
// Verify second value
result, found = c.Get(key)
tests.AssertEqual(t, true, found)
tests.AssertEqual(t, value2, result)
}
func TestInMemoryCache_Multiple_Keys(t *testing.T) {
// Setup
c := cache.NewInMemoryCache()
// Test data
testData := map[string]string{
"key1": "value1",
"key2": "value2",
@@ -152,22 +122,18 @@ func TestInMemoryCache_Multiple_Keys(t *testing.T) {
}
duration := 5 * time.Minute
// Set multiple values
for key, value := range testData {
c.Set(key, value, duration)
}
// Verify all values
for key, expectedValue := range testData {
result, found := c.Get(key)
tests.AssertEqual(t, true, found)
tests.AssertEqual(t, expectedValue, result)
}
// Delete one key
c.Delete("key2")
// Verify key2 is gone but others remain
result, found := c.Get("key2")
tests.AssertEqual(t, false, found)
if result != nil {
@@ -184,10 +150,8 @@ func TestInMemoryCache_Multiple_Keys(t *testing.T) {
}
func TestInMemoryCache_Complex_Objects(t *testing.T) {
// Setup
c := cache.NewInMemoryCache()
// Test with complex object (User struct)
user := &model.User{
ID: uuid.New(),
Username: "testuser",
@@ -196,15 +160,12 @@ func TestInMemoryCache_Complex_Objects(t *testing.T) {
key := "user:" + user.ID.String()
duration := 5 * time.Minute
// Set user in cache
c.Set(key, user, duration)
// Get user from cache
result, found := c.Get(key)
tests.AssertEqual(t, true, found)
tests.AssertNotNil(t, result)
// Verify it's the same user
cachedUser, ok := result.(*model.User)
tests.AssertEqual(t, true, ok)
tests.AssertEqual(t, user.ID, cachedUser.ID)
@@ -212,33 +173,27 @@ func TestInMemoryCache_Complex_Objects(t *testing.T) {
}
func TestInMemoryCache_GetOrSet_CacheHit(t *testing.T) {
// Setup
c := cache.NewInMemoryCache()
// Pre-populate cache
key := "test-key"
expectedValue := "cached-value"
c.Set(key, expectedValue, 5*time.Minute)
// Track if fetcher is called
fetcherCalled := false
fetcher := func() (string, error) {
fetcherCalled = true
return "fetcher-value", nil
}
// Use GetOrSet - should return cached value
result, err := cache.GetOrSet(c, key, 5*time.Minute, fetcher)
tests.AssertNoError(t, err)
tests.AssertEqual(t, expectedValue, result)
tests.AssertEqual(t, false, fetcherCalled) // Fetcher should not be called
tests.AssertEqual(t, false, fetcherCalled)
}
func TestInMemoryCache_GetOrSet_CacheMiss(t *testing.T) {
// Setup
c := cache.NewInMemoryCache()
// Track if fetcher is called
fetcherCalled := false
expectedValue := "fetcher-value"
fetcher := func() (string, error) {
@@ -248,35 +203,29 @@ func TestInMemoryCache_GetOrSet_CacheMiss(t *testing.T) {
key := "test-key"
// Use GetOrSet - should call fetcher and cache result
result, err := cache.GetOrSet(c, key, 5*time.Minute, fetcher)
tests.AssertNoError(t, err)
tests.AssertEqual(t, expectedValue, result)
tests.AssertEqual(t, true, fetcherCalled) // Fetcher should be called
tests.AssertEqual(t, true, fetcherCalled)
// Verify value is now cached
cachedResult, found := c.Get(key)
tests.AssertEqual(t, true, found)
tests.AssertEqual(t, expectedValue, cachedResult)
}
func TestInMemoryCache_GetOrSet_FetcherError(t *testing.T) {
// Setup
c := cache.NewInMemoryCache()
// Fetcher that returns error
fetcher := func() (string, error) {
return "", tests.ErrorForTesting("fetcher error")
}
key := "test-key"
// Use GetOrSet - should return error
result, err := cache.GetOrSet(c, key, 5*time.Minute, fetcher)
tests.AssertError(t, err, "")
tests.AssertEqual(t, "", result)
// Verify nothing is cached
cachedResult, found := c.Get(key)
tests.AssertEqual(t, false, found)
if cachedResult != nil {
@@ -285,10 +234,8 @@ func TestInMemoryCache_GetOrSet_FetcherError(t *testing.T) {
}
func TestInMemoryCache_TypeSafety(t *testing.T) {
// Setup
c := cache.NewInMemoryCache()
// Test type safety with GetOrSet
userFetcher := func() (*model.User, error) {
return &model.User{
ID: uuid.New(),
@@ -298,13 +245,11 @@ func TestInMemoryCache_TypeSafety(t *testing.T) {
key := "user-key"
// Use GetOrSet with User type
user, err := cache.GetOrSet(c, key, 5*time.Minute, userFetcher)
tests.AssertNoError(t, err)
tests.AssertNotNil(t, user)
tests.AssertEqual(t, "testuser", user.Username)
// Verify correct type is cached
cachedResult, found := c.Get(key)
tests.AssertEqual(t, true, found)
cachedUser, ok := cachedResult.(*model.User)
@@ -313,26 +258,21 @@ func TestInMemoryCache_TypeSafety(t *testing.T) {
}
func TestInMemoryCache_Concurrent_Access(t *testing.T) {
// Setup
c := cache.NewInMemoryCache()
// Test concurrent access
key := "concurrent-key"
value := "concurrent-value"
duration := 5 * time.Minute
// Run concurrent operations
done := make(chan bool, 3)
// Goroutine 1: Set value
go func() {
c.Set(key, value, duration)
done <- true
}()
// Goroutine 2: Get value
go func() {
time.Sleep(1 * time.Millisecond) // Small delay to ensure Set happens first
time.Sleep(1 * time.Millisecond)
result, found := c.Get(key)
if found {
tests.AssertEqual(t, value, result)
@@ -340,19 +280,16 @@ func TestInMemoryCache_Concurrent_Access(t *testing.T) {
done <- true
}()
// Goroutine 3: Delete value
go func() {
time.Sleep(2 * time.Millisecond) // Delay to ensure Set and Get happen first
time.Sleep(2 * time.Millisecond)
c.Delete(key)
done <- true
}()
// Wait for all goroutines to complete
for i := 0; i < 3; i++ {
<-done
}
// Verify value is deleted
result, found := c.Get(key)
tests.AssertEqual(t, false, found)
if result != nil {
@@ -361,7 +298,6 @@ func TestInMemoryCache_Concurrent_Access(t *testing.T) {
}
func TestServerStatusCache_GetStatus_NeedsRefresh(t *testing.T) {
// Setup
config := model.CacheConfig{
ExpirationTime: 5 * time.Minute,
ThrottleTime: 1 * time.Second,
@@ -371,14 +307,12 @@ func TestServerStatusCache_GetStatus_NeedsRefresh(t *testing.T) {
serviceName := "test-service"
// Initial call - should need refresh
status, needsRefresh := cache.GetStatus(serviceName)
tests.AssertEqual(t, model.StatusUnknown, status)
tests.AssertEqual(t, true, needsRefresh)
}
func TestServerStatusCache_UpdateStatus_GetStatus(t *testing.T) {
// Setup
config := model.CacheConfig{
ExpirationTime: 5 * time.Minute,
ThrottleTime: 1 * time.Second,
@@ -389,17 +323,14 @@ func TestServerStatusCache_UpdateStatus_GetStatus(t *testing.T) {
serviceName := "test-service"
expectedStatus := model.StatusRunning
// Update status
cache.UpdateStatus(serviceName, expectedStatus)
// Get status - should return cached value
status, needsRefresh := cache.GetStatus(serviceName)
tests.AssertEqual(t, expectedStatus, status)
tests.AssertEqual(t, false, needsRefresh)
}
func TestServerStatusCache_Throttling(t *testing.T) {
// Setup
config := model.CacheConfig{
ExpirationTime: 5 * time.Minute,
ThrottleTime: 100 * time.Millisecond,
@@ -409,58 +340,44 @@ func TestServerStatusCache_Throttling(t *testing.T) {
serviceName := "test-service"
// Update status
cache.UpdateStatus(serviceName, model.StatusRunning)
// Immediate call - should return cached value
status, needsRefresh := cache.GetStatus(serviceName)
tests.AssertEqual(t, model.StatusRunning, status)
tests.AssertEqual(t, false, needsRefresh)
// Call within throttle time - should return cached/default status
status, needsRefresh = cache.GetStatus(serviceName)
tests.AssertEqual(t, model.StatusRunning, status)
tests.AssertEqual(t, false, needsRefresh)
// Wait for throttle time to pass
time.Sleep(150 * time.Millisecond)
// Call after throttle time - don't check the specific value of needsRefresh
// as it may vary depending on the implementation
_, _ = cache.GetStatus(serviceName)
// Test passes if we reach this point without errors
}
func TestServerStatusCache_Expiration(t *testing.T) {
// Setup
config := model.CacheConfig{
ExpirationTime: 50 * time.Millisecond, // Very short expiration
ExpirationTime: 50 * time.Millisecond,
ThrottleTime: 10 * time.Millisecond,
DefaultStatus: model.StatusUnknown,
}
cache := model.NewServerStatusCache(config)
serviceName := "test-service"
// Update status
cache.UpdateStatus(serviceName, model.StatusRunning)
// Immediate call - should return cached value
status, needsRefresh := cache.GetStatus(serviceName)
tests.AssertEqual(t, model.StatusRunning, status)
tests.AssertEqual(t, false, needsRefresh)
// Wait for expiration
time.Sleep(60 * time.Millisecond)
// Call after expiration - should need refresh
status, needsRefresh = cache.GetStatus(serviceName)
tests.AssertEqual(t, true, needsRefresh)
}
func TestServerStatusCache_InvalidateStatus(t *testing.T) {
// Setup
config := model.CacheConfig{
ExpirationTime: 5 * time.Minute,
ThrottleTime: 1 * time.Second,
@@ -470,25 +387,20 @@ func TestServerStatusCache_InvalidateStatus(t *testing.T) {
serviceName := "test-service"
// Update status
cache.UpdateStatus(serviceName, model.StatusRunning)
// Verify it's cached
status, needsRefresh := cache.GetStatus(serviceName)
tests.AssertEqual(t, model.StatusRunning, status)
tests.AssertEqual(t, false, needsRefresh)
// Invalidate status
cache.InvalidateStatus(serviceName)
// Should need refresh now
status, needsRefresh = cache.GetStatus(serviceName)
tests.AssertEqual(t, model.StatusUnknown, status)
tests.AssertEqual(t, true, needsRefresh)
}
func TestServerStatusCache_Clear(t *testing.T) {
// Setup
config := model.CacheConfig{
ExpirationTime: 5 * time.Minute,
ThrottleTime: 1 * time.Second,
@@ -496,23 +408,19 @@ func TestServerStatusCache_Clear(t *testing.T) {
}
cache := model.NewServerStatusCache(config)
// Update multiple services
services := []string{"service1", "service2", "service3"}
for _, service := range services {
cache.UpdateStatus(service, model.StatusRunning)
}
// Verify all are cached
for _, service := range services {
status, needsRefresh := cache.GetStatus(service)
tests.AssertEqual(t, model.StatusRunning, status)
tests.AssertEqual(t, false, needsRefresh)
}
// Clear cache
cache.Clear()
// All should need refresh now
for _, service := range services {
status, needsRefresh := cache.GetStatus(service)
tests.AssertEqual(t, model.StatusUnknown, status)
@@ -521,30 +429,23 @@ func TestServerStatusCache_Clear(t *testing.T) {
}
func TestLookupCache_SetGetClear(t *testing.T) {
// Setup
cache := model.NewLookupCache()
// Test data
key := "lookup-key"
value := map[string]string{"test": "data"}
// Set value
cache.Set(key, value)
// Get value
result, found := cache.Get(key)
tests.AssertEqual(t, true, found)
tests.AssertNotNil(t, result)
// Verify it's the same data
resultMap, ok := result.(map[string]string)
tests.AssertEqual(t, true, ok)
tests.AssertEqual(t, "data", resultMap["test"])
// Clear cache
cache.Clear()
// Should be gone now
result, found = cache.Get(key)
tests.AssertEqual(t, false, found)
if result != nil {
@@ -553,7 +454,6 @@ func TestLookupCache_SetGetClear(t *testing.T) {
}
func TestServerConfigCache_Configuration(t *testing.T) {
// Setup
config := model.CacheConfig{
ExpirationTime: 5 * time.Minute,
ThrottleTime: 1 * time.Second,
@@ -571,17 +471,14 @@ func TestServerConfigCache_Configuration(t *testing.T) {
ConfigVersion: model.IntString(1),
}
// Initial get - should miss
result, found := cache.GetConfiguration(serverID)
tests.AssertEqual(t, false, found)
if result != nil {
t.Fatal("Expected nil result, got non-nil")
}
// Update cache
cache.UpdateConfiguration(serverID, configuration)
// Get from cache - should hit
result, found = cache.GetConfiguration(serverID)
tests.AssertEqual(t, true, found)
tests.AssertNotNil(t, result)
@@ -590,7 +487,6 @@ func TestServerConfigCache_Configuration(t *testing.T) {
}
func TestServerConfigCache_InvalidateServerCache(t *testing.T) {
// Setup
config := model.CacheConfig{
ExpirationTime: 5 * time.Minute,
ThrottleTime: 1 * time.Second,
@@ -602,11 +498,9 @@ func TestServerConfigCache_InvalidateServerCache(t *testing.T) {
configuration := model.Configuration{UdpPort: model.IntString(9231)}
assistRules := model.AssistRules{StabilityControlLevelMax: model.IntString(0)}
// Update multiple configs for server
cache.UpdateConfiguration(serverID, configuration)
cache.UpdateAssistRules(serverID, assistRules)
// Verify both are cached
configResult, found := cache.GetConfiguration(serverID)
tests.AssertEqual(t, true, found)
tests.AssertNotNil(t, configResult)
@@ -615,10 +509,8 @@ func TestServerConfigCache_InvalidateServerCache(t *testing.T) {
tests.AssertEqual(t, true, found)
tests.AssertNotNil(t, assistResult)
// Invalidate server cache
cache.InvalidateServerCache(serverID)
// Both should be gone
configResult, found = cache.GetConfiguration(serverID)
tests.AssertEqual(t, false, found)
if configResult != nil {

View File

@@ -12,25 +12,20 @@ import (
)
func TestConfigService_GetConfiguration_ValidFile(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Create test config files
err := helper.CreateTestConfigFiles()
tests.AssertNoError(t, err)
// Create repositories and service
configRepo := repository.NewConfigRepository(helper.DB)
serverRepo := repository.NewServerRepository(helper.DB)
configService := service.NewConfigService(configRepo, serverRepo)
// Test GetConfiguration
config, err := configService.GetConfiguration(helper.TestData.Server)
tests.AssertNoError(t, err)
tests.AssertNotNil(t, config)
// Verify the result is the expected configuration
tests.AssertEqual(t, model.IntString(9231), config.UdpPort)
tests.AssertEqual(t, model.IntString(9232), config.TcpPort)
tests.AssertEqual(t, model.IntString(30), config.MaxConnections)
@@ -39,51 +34,21 @@ func TestConfigService_GetConfiguration_ValidFile(t *testing.T) {
tests.AssertEqual(t, model.IntString(1), config.ConfigVersion)
}
func TestConfigService_GetConfiguration_MissingFile(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Create server directory but no config files
serverConfigDir := filepath.Join(helper.TestData.Server.Path, "cfg")
err := os.MkdirAll(serverConfigDir, 0755)
tests.AssertNoError(t, err)
// Create repositories and service
configRepo := repository.NewConfigRepository(helper.DB)
serverRepo := repository.NewServerRepository(helper.DB)
configService := service.NewConfigService(configRepo, serverRepo)
// Test GetConfiguration for missing file
config, err := configService.GetConfiguration(helper.TestData.Server)
if err == nil {
t.Fatal("Expected error for missing file, got nil")
}
if config != nil {
t.Fatal("Expected nil config, got non-nil")
}
}
func TestConfigService_GetEventConfig_ValidFile(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Create test config files
err := helper.CreateTestConfigFiles()
tests.AssertNoError(t, err)
// Create repositories and service
configRepo := repository.NewConfigRepository(helper.DB)
serverRepo := repository.NewServerRepository(helper.DB)
configService := service.NewConfigService(configRepo, serverRepo)
// Test GetEventConfig
eventConfig, err := configService.GetEventConfig(helper.TestData.Server)
tests.AssertNoError(t, err)
tests.AssertNotNil(t, eventConfig)
// Verify the result is the expected event configuration
tests.AssertEqual(t, "spa", eventConfig.Track)
tests.AssertEqual(t, model.IntString(80), eventConfig.PreRaceWaitingTimeSeconds)
tests.AssertEqual(t, model.IntString(120), eventConfig.SessionOverTimeSeconds)
@@ -91,7 +56,6 @@ func TestConfigService_GetEventConfig_ValidFile(t *testing.T) {
tests.AssertEqual(t, float64(0.3), eventConfig.CloudLevel)
tests.AssertEqual(t, float64(0.0), eventConfig.Rain)
// Verify sessions
tests.AssertEqual(t, 3, len(eventConfig.Sessions))
if len(eventConfig.Sessions) > 0 {
tests.AssertEqual(t, model.SessionPractice, eventConfig.Sessions[0].SessionType)
@@ -101,20 +65,16 @@ func TestConfigService_GetEventConfig_ValidFile(t *testing.T) {
func TestConfigService_SaveConfiguration_Success(t *testing.T) {
t.Skip("Temporarily disabled due to path issues")
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Create test config files
err := helper.CreateTestConfigFiles()
tests.AssertNoError(t, err)
// Create repositories and service
configRepo := repository.NewConfigRepository(helper.DB)
serverRepo := repository.NewServerRepository(helper.DB)
configService := service.NewConfigService(configRepo, serverRepo)
// Prepare new configuration
newConfig := &model.Configuration{
UdpPort: model.IntString(9999),
TcpPort: model.IntString(10000),
@@ -124,16 +84,13 @@ func TestConfigService_SaveConfiguration_Success(t *testing.T) {
ConfigVersion: model.IntString(2),
}
// Test SaveConfiguration
err = configService.SaveConfiguration(helper.TestData.Server, newConfig)
tests.AssertNoError(t, err)
// Verify the configuration was saved
configPath := filepath.Join(helper.TestData.Server.Path, "cfg", "configuration.json")
fileContent, err := os.ReadFile(configPath)
tests.AssertNoError(t, err)
// Convert from UTF-16 to UTF-8 for verification
utf8Content, err := service.DecodeUTF16LEBOM(fileContent)
tests.AssertNoError(t, err)
@@ -141,7 +98,6 @@ func TestConfigService_SaveConfiguration_Success(t *testing.T) {
err = json.Unmarshal(utf8Content, &savedConfig)
tests.AssertNoError(t, err)
// Verify the saved values
tests.AssertEqual(t, "9999", savedConfig["udpPort"])
tests.AssertEqual(t, "10000", savedConfig["tcpPort"])
tests.AssertEqual(t, "40", savedConfig["maxConnections"])
@@ -151,25 +107,20 @@ func TestConfigService_SaveConfiguration_Success(t *testing.T) {
}
func TestConfigService_LoadConfigs_Success(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Create test config files
err := helper.CreateTestConfigFiles()
tests.AssertNoError(t, err)
// Create repositories and service
configRepo := repository.NewConfigRepository(helper.DB)
serverRepo := repository.NewServerRepository(helper.DB)
configService := service.NewConfigService(configRepo, serverRepo)
// Test LoadConfigs
configs, err := configService.LoadConfigs(helper.TestData.Server)
tests.AssertNoError(t, err)
tests.AssertNotNil(t, configs)
// Verify all configurations are loaded
tests.AssertEqual(t, model.IntString(9231), configs.Configuration.UdpPort)
tests.AssertEqual(t, model.IntString(9232), configs.Configuration.TcpPort)
tests.AssertEqual(t, "Test ACC Server", configs.Settings.ServerName)
@@ -182,46 +133,17 @@ func TestConfigService_LoadConfigs_Success(t *testing.T) {
tests.AssertEqual(t, model.IntString(600), configs.EventRules.PitWindowLengthSec)
}
func TestConfigService_LoadConfigs_MissingFiles(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Create server directory but no config files
serverConfigDir := filepath.Join(helper.TestData.Server.Path, "cfg")
err := os.MkdirAll(serverConfigDir, 0755)
tests.AssertNoError(t, err)
// Create repositories and service
configRepo := repository.NewConfigRepository(helper.DB)
serverRepo := repository.NewServerRepository(helper.DB)
configService := service.NewConfigService(configRepo, serverRepo)
// Test LoadConfigs with missing files
configs, err := configService.LoadConfigs(helper.TestData.Server)
if err == nil {
t.Fatal("Expected error for missing files, got nil")
}
if configs != nil {
t.Fatal("Expected nil configs, got non-nil")
}
}
func TestConfigService_MalformedJSON(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Create malformed config file
err := helper.CreateMalformedConfigFile("configuration.json")
tests.AssertNoError(t, err)
// Create repositories and service
configRepo := repository.NewConfigRepository(helper.DB)
serverRepo := repository.NewServerRepository(helper.DB)
configService := service.NewConfigService(configRepo, serverRepo)
// Test GetConfiguration with malformed JSON
config, err := configService.GetConfiguration(helper.TestData.Server)
if err == nil {
t.Fatal("Expected error for malformed JSON, got nil")
@@ -232,31 +154,24 @@ func TestConfigService_MalformedJSON(t *testing.T) {
}
func TestConfigService_UTF16_Encoding(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Create test config files
err := helper.CreateTestConfigFiles()
tests.AssertNoError(t, err)
// Test UTF-16 encoding and decoding
originalData := `{"udpPort": "9231", "tcpPort": "9232"}`
// Encode to UTF-16 LE BOM
encoded, err := service.EncodeUTF16LEBOM([]byte(originalData))
tests.AssertNoError(t, err)
// Decode back to UTF-8
decoded, err := service.DecodeUTF16LEBOM(encoded)
tests.AssertNoError(t, err)
// Verify it matches original
tests.AssertEqual(t, originalData, string(decoded))
}
func TestConfigService_DecodeFileName(t *testing.T) {
// Test that all supported file names have decoders
testCases := []string{
"configuration.json",
"assistRules.json",
@@ -272,7 +187,6 @@ func TestConfigService_DecodeFileName(t *testing.T) {
})
}
// Test invalid filename
decoder := service.DecodeFileName("invalid.json")
if decoder != nil {
t.Fatal("Expected nil decoder for invalid filename, got non-nil")
@@ -280,22 +194,18 @@ func TestConfigService_DecodeFileName(t *testing.T) {
}
func TestConfigService_IntString_Conversion(t *testing.T) {
// Test IntString unmarshaling from string
var intStr model.IntString
// Test string input
err := json.Unmarshal([]byte(`"123"`), &intStr)
tests.AssertNoError(t, err)
tests.AssertEqual(t, 123, intStr.ToInt())
tests.AssertEqual(t, "123", intStr.ToString())
// Test int input
err = json.Unmarshal([]byte(`456`), &intStr)
tests.AssertNoError(t, err)
tests.AssertEqual(t, 456, intStr.ToInt())
tests.AssertEqual(t, "456", intStr.ToString())
// Test empty string
err = json.Unmarshal([]byte(`""`), &intStr)
tests.AssertNoError(t, err)
tests.AssertEqual(t, 0, intStr.ToInt())
@@ -303,28 +213,23 @@ func TestConfigService_IntString_Conversion(t *testing.T) {
}
func TestConfigService_IntBool_Conversion(t *testing.T) {
// Test IntBool unmarshaling from int
var intBool model.IntBool
// Test int input (1 = true)
err := json.Unmarshal([]byte(`1`), &intBool)
tests.AssertNoError(t, err)
tests.AssertEqual(t, 1, intBool.ToInt())
tests.AssertEqual(t, true, intBool.ToBool())
// Test int input (0 = false)
err = json.Unmarshal([]byte(`0`), &intBool)
tests.AssertNoError(t, err)
tests.AssertEqual(t, 0, intBool.ToInt())
tests.AssertEqual(t, false, intBool.ToBool())
// Test bool input (true)
err = json.Unmarshal([]byte(`true`), &intBool)
tests.AssertNoError(t, err)
tests.AssertEqual(t, 1, intBool.ToInt())
tests.AssertEqual(t, true, intBool.ToBool())
// Test bool input (false)
err = json.Unmarshal([]byte(`false`), &intBool)
tests.AssertNoError(t, err)
tests.AssertEqual(t, 0, intBool.ToInt())
@@ -332,25 +237,20 @@ func TestConfigService_IntBool_Conversion(t *testing.T) {
}
func TestConfigService_Caching_Configuration(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Create test config files (already UTF-16 encoded)
err := helper.CreateTestConfigFiles()
tests.AssertNoError(t, err)
// Create repositories and service
configRepo := repository.NewConfigRepository(helper.DB)
serverRepo := repository.NewServerRepository(helper.DB)
configService := service.NewConfigService(configRepo, serverRepo)
// First call - should load from disk
config1, err := configService.GetConfiguration(helper.TestData.Server)
tests.AssertNoError(t, err)
tests.AssertNotNil(t, config1)
// Modify the file on disk with UTF-16 encoding
configPath := filepath.Join(helper.TestData.Server.Path, "cfg", "configuration.json")
modifiedContent := `{"udpPort": "5555", "tcpPort": "5556"}`
utf16Modified, err := service.EncodeUTF16LEBOM([]byte(modifiedContent))
@@ -359,36 +259,29 @@ func TestConfigService_Caching_Configuration(t *testing.T) {
err = os.WriteFile(configPath, utf16Modified, 0644)
tests.AssertNoError(t, err)
// Second call - should return cached result (not the modified file)
config2, err := configService.GetConfiguration(helper.TestData.Server)
tests.AssertNoError(t, err)
tests.AssertNotNil(t, config2)
// Should still have the original cached values
tests.AssertEqual(t, model.IntString(9231), config2.UdpPort)
tests.AssertEqual(t, model.IntString(9232), config2.TcpPort)
}
func TestConfigService_Caching_EventConfig(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Create test config files (already UTF-16 encoded)
err := helper.CreateTestConfigFiles()
tests.AssertNoError(t, err)
// Create repositories and service
configRepo := repository.NewConfigRepository(helper.DB)
serverRepo := repository.NewServerRepository(helper.DB)
configService := service.NewConfigService(configRepo, serverRepo)
// First call - should load from disk
event1, err := configService.GetEventConfig(helper.TestData.Server)
tests.AssertNoError(t, err)
tests.AssertNotNil(t, event1)
// Modify the file on disk with UTF-16 encoding
configPath := filepath.Join(helper.TestData.Server.Path, "cfg", "event.json")
modifiedContent := `{"track": "monza", "preRaceWaitingTimeSeconds": "60"}`
utf16Modified, err := service.EncodeUTF16LEBOM([]byte(modifiedContent))
@@ -397,12 +290,10 @@ func TestConfigService_Caching_EventConfig(t *testing.T) {
err = os.WriteFile(configPath, utf16Modified, 0644)
tests.AssertNoError(t, err)
// Second call - should return cached result (not the modified file)
event2, err := configService.GetEventConfig(helper.TestData.Server)
tests.AssertNoError(t, err)
tests.AssertNotNil(t, event2)
// Should still have the original cached values
tests.AssertEqual(t, "spa", event2.Track)
tests.AssertEqual(t, model.IntString(80), event2.PreRaceWaitingTimeSeconds)
}

View File

@@ -15,11 +15,9 @@ import (
)
func TestStateHistoryService_GetAll_Success(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Ensure the state_histories table exists
if !helper.DB.Migrator().HasTable(&model.StateHistory{}) {
err := helper.DB.Migrator().CreateTable(&model.StateHistory{})
if err != nil {
@@ -27,22 +25,17 @@ func TestStateHistoryService_GetAll_Success(t *testing.T) {
}
}
// Use real repository like other service tests
repo := repository.NewStateHistoryRepository(helper.DB)
stateHistoryService := service.NewStateHistoryService(repo)
// Insert test data directly into DB
testData := testdata.NewStateHistoryTestData(helper.TestData.ServerID)
history := testData.CreateStateHistory(model.SessionPractice, "spa", 5, uuid.New())
err := repo.Insert(helper.CreateContext(), &history)
tests.AssertNoError(t, err)
// Create proper Fiber context
app := fiber.New()
ctx := helper.CreateFiberCtx()
defer helper.ReleaseFiberCtx(app, ctx)
// Test GetAll
filter := testdata.CreateBasicFilter(helper.TestData.ServerID.String())
result, err := stateHistoryService.GetAll(ctx, filter)
@@ -54,11 +47,9 @@ func TestStateHistoryService_GetAll_Success(t *testing.T) {
}
func TestStateHistoryService_GetAll_WithFilter(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Ensure the state_histories table exists
if !helper.DB.Migrator().HasTable(&model.StateHistory{}) {
err := helper.DB.Migrator().CreateTable(&model.StateHistory{})
if err != nil {
@@ -69,7 +60,6 @@ func TestStateHistoryService_GetAll_WithFilter(t *testing.T) {
repo := repository.NewStateHistoryRepository(helper.DB)
stateHistoryService := service.NewStateHistoryService(repo)
// Insert test data with different sessions
testData := testdata.NewStateHistoryTestData(helper.TestData.ServerID)
practiceHistory := testData.CreateStateHistory(model.SessionPractice, "spa", 5, uuid.New())
raceHistory := testData.CreateStateHistory(model.SessionRace, "spa", 10, uuid.New())
@@ -79,12 +69,10 @@ func TestStateHistoryService_GetAll_WithFilter(t *testing.T) {
err = repo.Insert(helper.CreateContext(), &raceHistory)
tests.AssertNoError(t, err)
// Create proper Fiber context
app := fiber.New()
ctx := helper.CreateFiberCtx()
defer helper.ReleaseFiberCtx(app, ctx)
// Test GetAll with session filter
filter := testdata.CreateFilterWithSession(helper.TestData.ServerID.String(), model.SessionRace)
result, err := stateHistoryService.GetAll(ctx, filter)
@@ -96,11 +84,9 @@ func TestStateHistoryService_GetAll_WithFilter(t *testing.T) {
}
func TestStateHistoryService_GetAll_NoData(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Ensure the state_histories table exists
if !helper.DB.Migrator().HasTable(&model.StateHistory{}) {
err := helper.DB.Migrator().CreateTable(&model.StateHistory{})
if err != nil {
@@ -111,12 +97,10 @@ func TestStateHistoryService_GetAll_NoData(t *testing.T) {
repo := repository.NewStateHistoryRepository(helper.DB)
stateHistoryService := service.NewStateHistoryService(repo)
// Create proper Fiber context
app := fiber.New()
ctx := helper.CreateFiberCtx()
defer helper.ReleaseFiberCtx(app, ctx)
// Test GetAll with no data
filter := testdata.CreateBasicFilter(helper.TestData.ServerID.String())
result, err := stateHistoryService.GetAll(ctx, filter)
@@ -126,11 +110,9 @@ func TestStateHistoryService_GetAll_NoData(t *testing.T) {
}
func TestStateHistoryService_Insert_Success(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Ensure the state_histories table exists
if !helper.DB.Migrator().HasTable(&model.StateHistory{}) {
err := helper.DB.Migrator().CreateTable(&model.StateHistory{})
if err != nil {
@@ -141,20 +123,16 @@ func TestStateHistoryService_Insert_Success(t *testing.T) {
repo := repository.NewStateHistoryRepository(helper.DB)
stateHistoryService := service.NewStateHistoryService(repo)
// Create test data
testData := testdata.NewStateHistoryTestData(helper.TestData.ServerID)
history := testData.CreateStateHistory(model.SessionPractice, "spa", 5, uuid.New())
// Create proper Fiber context
app := fiber.New()
ctx := helper.CreateFiberCtx()
defer helper.ReleaseFiberCtx(app, ctx)
// Test Insert
err := stateHistoryService.Insert(ctx, &history)
tests.AssertNoError(t, err)
// Verify data was inserted
filter := testdata.CreateBasicFilter(helper.TestData.ServerID.String())
result, err := stateHistoryService.GetAll(ctx, filter)
tests.AssertNoError(t, err)
@@ -162,11 +140,9 @@ func TestStateHistoryService_Insert_Success(t *testing.T) {
}
func TestStateHistoryService_GetLastSessionID_Success(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Ensure the state_histories table exists
if !helper.DB.Migrator().HasTable(&model.StateHistory{}) {
err := helper.DB.Migrator().CreateTable(&model.StateHistory{})
if err != nil {
@@ -177,30 +153,25 @@ func TestStateHistoryService_GetLastSessionID_Success(t *testing.T) {
repo := repository.NewStateHistoryRepository(helper.DB)
stateHistoryService := service.NewStateHistoryService(repo)
// Insert test data
testData := testdata.NewStateHistoryTestData(helper.TestData.ServerID)
sessionID := uuid.New()
history := testData.CreateStateHistory(model.SessionPractice, "spa", 5, sessionID)
err := repo.Insert(helper.CreateContext(), &history)
tests.AssertNoError(t, err)
// Create proper Fiber context
app := fiber.New()
ctx := helper.CreateFiberCtx()
defer helper.ReleaseFiberCtx(app, ctx)
// Test GetLastSessionID
lastSessionID, err := stateHistoryService.GetLastSessionID(ctx, helper.TestData.ServerID)
tests.AssertNoError(t, err)
tests.AssertEqual(t, sessionID, lastSessionID)
}
func TestStateHistoryService_GetLastSessionID_NoData(t *testing.T) {
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Ensure the state_histories table exists
if !helper.DB.Migrator().HasTable(&model.StateHistory{}) {
err := helper.DB.Migrator().CreateTable(&model.StateHistory{})
if err != nil {
@@ -211,26 +182,21 @@ func TestStateHistoryService_GetLastSessionID_NoData(t *testing.T) {
repo := repository.NewStateHistoryRepository(helper.DB)
stateHistoryService := service.NewStateHistoryService(repo)
// Create proper Fiber context
app := fiber.New()
ctx := helper.CreateFiberCtx()
defer helper.ReleaseFiberCtx(app, ctx)
// Test GetLastSessionID with no data
lastSessionID, err := stateHistoryService.GetLastSessionID(ctx, helper.TestData.ServerID)
tests.AssertNoError(t, err)
tests.AssertEqual(t, uuid.Nil, lastSessionID)
}
func TestStateHistoryService_GetStatistics_Success(t *testing.T) {
// This test might fail due to database setup issues
t.Skip("Skipping test as it's dependent on database migration")
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Ensure the state_histories table exists
if !helper.DB.Migrator().HasTable(&model.StateHistory{}) {
err := helper.DB.Migrator().CreateTable(&model.StateHistory{})
if err != nil {
@@ -241,10 +207,8 @@ func TestStateHistoryService_GetStatistics_Success(t *testing.T) {
repo := repository.NewStateHistoryRepository(helper.DB)
stateHistoryService := service.NewStateHistoryService(repo)
// Insert test data with varying player counts
_ = testdata.NewStateHistoryTestData(helper.TestData.ServerID)
// Create entries with different sessions and player counts
sessionID1 := uuid.New()
sessionID2 := uuid.New()
@@ -291,12 +255,10 @@ func TestStateHistoryService_GetStatistics_Success(t *testing.T) {
tests.AssertNoError(t, err)
}
// Create proper Fiber context
app := fiber.New()
ctx := helper.CreateFiberCtx()
defer helper.ReleaseFiberCtx(app, ctx)
// Test GetStatistics
filter := &model.StateHistoryFilter{
ServerBasedFilter: model.ServerBasedFilter{
ServerID: helper.TestData.ServerID.String(),
@@ -311,17 +273,14 @@ func TestStateHistoryService_GetStatistics_Success(t *testing.T) {
tests.AssertNoError(t, err)
tests.AssertNotNil(t, stats)
// Verify statistics
tests.AssertEqual(t, 15, stats.PeakPlayers) // Maximum player count
tests.AssertEqual(t, 2, stats.TotalSessions) // Two unique sessions
tests.AssertEqual(t, 15, stats.PeakPlayers)
tests.AssertEqual(t, 2, stats.TotalSessions)
// Average should be (5+10+15)/3 = 10
expectedAverage := float64(5+10+15) / 3.0
if stats.AveragePlayers != expectedAverage {
t.Errorf("Expected average players %.1f, got %.1f", expectedAverage, stats.AveragePlayers)
}
// Verify other statistics components exist
tests.AssertNotNil(t, stats.PlayerCountOverTime)
tests.AssertNotNil(t, stats.SessionTypes)
tests.AssertNotNil(t, stats.DailyActivity)
@@ -329,14 +288,11 @@ func TestStateHistoryService_GetStatistics_Success(t *testing.T) {
}
func TestStateHistoryService_GetStatistics_NoData(t *testing.T) {
// This test might fail due to database setup issues
t.Skip("Skipping test as it's dependent on database migration")
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Ensure the state_histories table exists
if !helper.DB.Migrator().HasTable(&model.StateHistory{}) {
err := helper.DB.Migrator().CreateTable(&model.StateHistory{})
if err != nil {
@@ -347,19 +303,16 @@ func TestStateHistoryService_GetStatistics_NoData(t *testing.T) {
repo := repository.NewStateHistoryRepository(helper.DB)
stateHistoryService := service.NewStateHistoryService(repo)
// Create proper Fiber context
app := fiber.New()
ctx := helper.CreateFiberCtx()
defer helper.ReleaseFiberCtx(app, ctx)
// Test GetStatistics with no data
filter := testdata.CreateBasicFilter(helper.TestData.ServerID.String())
stats, err := stateHistoryService.GetStatistics(ctx, filter)
tests.AssertNoError(t, err)
tests.AssertNotNil(t, stats)
// Verify empty statistics
tests.AssertEqual(t, 0, stats.PeakPlayers)
tests.AssertEqual(t, 0.0, stats.AveragePlayers)
tests.AssertEqual(t, 0, stats.TotalSessions)
@@ -367,43 +320,32 @@ func TestStateHistoryService_GetStatistics_NoData(t *testing.T) {
}
func TestStateHistoryService_LogParsingWorkflow(t *testing.T) {
// Skip this test as it's unreliable and not critical
t.Skip("Skipping log parsing test as it's not critical to the service functionality")
// This test simulates the actual log parsing workflow
// Setup
helper := tests.NewTestHelper(t)
defer helper.Cleanup()
// Insert test server
err := helper.InsertTestServer()
tests.AssertNoError(t, err)
server := helper.TestData.Server
// Track state changes
var stateChanges []*model.ServerState
onStateChange := func(state *model.ServerState, changes ...tracking.StateChange) {
// Use pointer to avoid copying mutex
stateChanges = append(stateChanges, state)
}
// Create AccServerInstance (this is what the real server service does)
instance := tracking.NewAccServerInstance(server, onStateChange)
// Simulate processing log lines (this tests the actual HandleLogLine functionality)
logLines := testdata.SampleLogLines
for _, line := range logLines {
instance.HandleLogLine(line)
}
// Verify state changes were detected
if len(stateChanges) == 0 {
t.Error("Expected state changes from log parsing, got none")
}
// Verify session changes were parsed correctly
expectedSessions := []model.TrackSession{model.SessionPractice, model.SessionQualify, model.SessionRace}
sessionIndex := 0
@@ -416,18 +358,15 @@ func TestStateHistoryService_LogParsingWorkflow(t *testing.T) {
}
}
// Verify player count changes were tracked
if len(stateChanges) > 0 {
finalState := stateChanges[len(stateChanges)-1]
tests.AssertEqual(t, 0, finalState.PlayerCount) // Should end with 0 players
tests.AssertEqual(t, 0, finalState.PlayerCount)
}
}
func TestStateHistoryService_SessionChangeTracking(t *testing.T) {
// Skip this test as it's unreliable
t.Skip("Skipping session tracking test as it's unreliable in CI environments")
// Test session change detection
server := &model.Server{
ID: uuid.New(),
Name: "Test Server",
@@ -437,7 +376,6 @@ func TestStateHistoryService_SessionChangeTracking(t *testing.T) {
onStateChange := func(state *model.ServerState, changes ...tracking.StateChange) {
for _, change := range changes {
if change == tracking.Session {
// Create a copy of the session to avoid later mutations
sessionCopy := state.Session
sessionChanges = append(sessionChanges, sessionCopy)
}
@@ -446,22 +384,17 @@ func TestStateHistoryService_SessionChangeTracking(t *testing.T) {
instance := tracking.NewAccServerInstance(server, onStateChange)
// We'll add one session change at a time and wait briefly to ensure they're processed in order
for _, expected := range testdata.ExpectedSessionChanges {
line := string("[2024-01-15 14:30:25.123] Session changed: " + expected.From + " -> " + expected.To)
instance.HandleLogLine(line)
// Small pause to ensure log processing completes
time.Sleep(10 * time.Millisecond)
}
// Check if we have any session changes
if len(sessionChanges) == 0 {
t.Error("No session changes detected")
return
}
// Just verify the last session change matches what we expect
// This is more reliable than checking the entire sequence
lastExpected := testdata.ExpectedSessionChanges[len(testdata.ExpectedSessionChanges)-1].To
lastActual := sessionChanges[len(sessionChanges)-1]
if lastActual != lastExpected {
@@ -470,10 +403,8 @@ func TestStateHistoryService_SessionChangeTracking(t *testing.T) {
}
func TestStateHistoryService_PlayerCountTracking(t *testing.T) {
// Skip this test as it's unreliable
t.Skip("Skipping player count tracking test as it's unreliable in CI environments")
// Test player count change detection
server := &model.Server{
ID: uuid.New(),
Name: "Test Server",
@@ -490,7 +421,6 @@ func TestStateHistoryService_PlayerCountTracking(t *testing.T) {
instance := tracking.NewAccServerInstance(server, onStateChange)
// Test each expected player count change
expectedCounts := testdata.ExpectedPlayerCounts
logLines := []string{
"[2024-01-15 14:30:30.456] 1 client(s) online",
@@ -499,7 +429,7 @@ func TestStateHistoryService_PlayerCountTracking(t *testing.T) {
"[2024-01-15 14:35:05.789] 8 client(s) online",
"[2024-01-15 14:40:05.456] 12 client(s) online",
"[2024-01-15 14:45:00.789] 15 client(s) online",
"[2024-01-15 14:50:00.789] Removing dead connection", // Should decrease by 1
"[2024-01-15 14:50:00.789] Removing dead connection",
"[2024-01-15 15:00:00.789] 0 client(s) online",
}
@@ -507,7 +437,6 @@ func TestStateHistoryService_PlayerCountTracking(t *testing.T) {
instance.HandleLogLine(line)
}
// Verify all player count changes were detected
tests.AssertEqual(t, len(expectedCounts), len(playerCounts))
for i, expected := range expectedCounts {
if i < len(playerCounts) {
@@ -517,10 +446,8 @@ func TestStateHistoryService_PlayerCountTracking(t *testing.T) {
}
func TestStateHistoryService_EdgeCases(t *testing.T) {
// Skip this test as it's unreliable
t.Skip("Skipping edge cases test as it's unreliable in CI environments")
// Test edge cases in log parsing
server := &model.Server{
ID: uuid.New(),
Name: "Test Server",
@@ -528,34 +455,30 @@ func TestStateHistoryService_EdgeCases(t *testing.T) {
var stateChanges []*model.ServerState
onStateChange := func(state *model.ServerState, changes ...tracking.StateChange) {
// Create a copy of the state to avoid later mutations affecting our saved state
stateCopy := *state
stateChanges = append(stateChanges, &stateCopy)
}
instance := tracking.NewAccServerInstance(server, onStateChange)
// Test edge cases
edgeCaseLines := []string{
"[2024-01-15 14:30:25.123] Some unrelated log line", // Should be ignored
"[2024-01-15 14:30:25.123] Session changed: NONE -> PRACTICE", // Valid session change
"[2024-01-15 14:30:30.456] 0 client(s) online", // Zero players
"[2024-01-15 14:30:35.789] -1 client(s) online", // Invalid negative (should be ignored)
"[2024-01-15 14:30:40.789] 30 client(s) online", // High but valid player count
"[2024-01-15 14:30:45.789] invalid client(s) online", // Invalid format (should be ignored)
"[2024-01-15 14:30:25.123] Some unrelated log line",
"[2024-01-15 14:30:25.123] Session changed: NONE -> PRACTICE",
"[2024-01-15 14:30:30.456] 0 client(s) online",
"[2024-01-15 14:30:35.789] -1 client(s) online",
"[2024-01-15 14:30:40.789] 30 client(s) online",
"[2024-01-15 14:30:45.789] invalid client(s) online",
}
for _, line := range edgeCaseLines {
instance.HandleLogLine(line)
}
// Verify we have some state changes
if len(stateChanges) == 0 {
t.Errorf("Expected state changes, got none")
return
}
// Look for a state with 30 players - might be in any position due to concurrency
found30Players := false
for _, state := range stateChanges {
if state.PlayerCount == 30 {
@@ -564,8 +487,6 @@ func TestStateHistoryService_EdgeCases(t *testing.T) {
}
}
// Mark the test as passed if we found at least one state with the expected value
// This makes the test more resilient to timing/ordering differences
if !found30Players {
t.Log("Player counts in recorded states:")
for i, state := range stateChanges {
@@ -576,10 +497,8 @@ func TestStateHistoryService_EdgeCases(t *testing.T) {
}
func TestStateHistoryService_SessionStartTracking(t *testing.T) {
// Skip this test as it's unreliable
t.Skip("Skipping session start tracking test as it's unreliable in CI environments")
// Test that session start times are tracked correctly
server := &model.Server{
ID: uuid.New(),
Name: "Test Server",
@@ -596,16 +515,13 @@ func TestStateHistoryService_SessionStartTracking(t *testing.T) {
instance := tracking.NewAccServerInstance(server, onStateChange)
// Simulate session starting when players join
startTime := time.Now()
instance.HandleLogLine("[2024-01-15 14:30:30.456] 1 client(s) online") // First player joins
instance.HandleLogLine("[2024-01-15 14:30:30.456] 1 client(s) online")
// Verify session start was recorded
if len(sessionStarts) == 0 {
t.Error("Expected session start to be recorded when first player joins")
}
// Session start should be close to when we processed the log line
if len(sessionStarts) > 0 {
timeDiff := sessionStarts[0].Sub(startTime)
if timeDiff > time.Second || timeDiff < -time.Second {