add step list for server creation
This commit is contained in:
@@ -10,24 +10,19 @@ import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// GenerateTestToken creates a JWT token for testing purposes
|
||||
func GenerateTestToken() (string, error) {
|
||||
// Create test user
|
||||
user := &model.User{
|
||||
ID: uuid.New(),
|
||||
Username: "test_user",
|
||||
RoleID: uuid.New(),
|
||||
}
|
||||
|
||||
// Use the environment JWT_SECRET for consistency with middleware
|
||||
testSecret := os.Getenv("JWT_SECRET")
|
||||
if testSecret == "" {
|
||||
// Fallback to a test secret if env var is not set
|
||||
testSecret = "test-secret-that-is-at-least-32-bytes-long-for-security"
|
||||
}
|
||||
jwtHandler := jwt.NewJWTHandler(testSecret)
|
||||
|
||||
// Generate JWT token
|
||||
token, err := jwtHandler.GenerateToken(user.ID.String())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to generate test token: %w", err)
|
||||
@@ -36,8 +31,6 @@ func GenerateTestToken() (string, error) {
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// MustGenerateTestToken generates a test token and panics if it fails
|
||||
// This is useful for test setup where failing to generate a token is a fatal error
|
||||
func MustGenerateTestToken() string {
|
||||
token, err := GenerateTestToken()
|
||||
if err != nil {
|
||||
@@ -46,24 +39,19 @@ func MustGenerateTestToken() string {
|
||||
return token
|
||||
}
|
||||
|
||||
// GenerateTestTokenWithExpiry creates a JWT token with a specific expiry time
|
||||
func GenerateTestTokenWithExpiry(expiryTime time.Time) (string, error) {
|
||||
// Use the environment JWT_SECRET for consistency with middleware
|
||||
testSecret := os.Getenv("JWT_SECRET")
|
||||
if testSecret == "" {
|
||||
// Fallback to a test secret if env var is not set
|
||||
testSecret = "test-secret-that-is-at-least-32-bytes-long-for-security"
|
||||
}
|
||||
jwtHandler := jwt.NewJWTHandler(testSecret)
|
||||
|
||||
// Create test user
|
||||
user := &model.User{
|
||||
ID: uuid.New(),
|
||||
Username: "test_user",
|
||||
RoleID: uuid.New(),
|
||||
}
|
||||
|
||||
// Generate JWT token with custom expiry
|
||||
token, err := jwtHandler.GenerateTokenWithExpiry(user, expiryTime)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to generate test token with expiry: %w", err)
|
||||
@@ -72,8 +60,6 @@ func GenerateTestTokenWithExpiry(expiryTime time.Time) (string, error) {
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// AddAuthHeader adds a test auth token to the request headers
|
||||
// This is a convenience method for tests that need to authenticate requests
|
||||
func AddAuthHeader(headers map[string]string) (map[string]string, error) {
|
||||
token, err := GenerateTestToken()
|
||||
if err != nil {
|
||||
@@ -88,7 +74,6 @@ func AddAuthHeader(headers map[string]string) (map[string]string, error) {
|
||||
return headers, nil
|
||||
}
|
||||
|
||||
// MustAddAuthHeader adds a test auth token to the request headers and panics if it fails
|
||||
func MustAddAuthHeader(headers map[string]string) map[string]string {
|
||||
result, err := AddAuthHeader(headers)
|
||||
if err != nil {
|
||||
|
||||
@@ -8,26 +8,20 @@ import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// MockAuthMiddleware provides a test implementation of AuthMiddleware
|
||||
// that can be used as a drop-in replacement for the real AuthMiddleware
|
||||
type MockAuthMiddleware struct{}
|
||||
|
||||
// NewMockAuthMiddleware creates a new MockAuthMiddleware
|
||||
func NewMockAuthMiddleware() *MockAuthMiddleware {
|
||||
return &MockAuthMiddleware{}
|
||||
}
|
||||
|
||||
// Authenticate is a middleware that allows all requests without authentication for testing
|
||||
func (m *MockAuthMiddleware) Authenticate(ctx *fiber.Ctx) error {
|
||||
// Set a mock user ID in context
|
||||
mockUserID := uuid.New().String()
|
||||
ctx.Locals("userID", mockUserID)
|
||||
|
||||
// Set mock user info
|
||||
mockUserInfo := &middleware.CachedUserInfo{
|
||||
UserID: mockUserID,
|
||||
Username: "test_user",
|
||||
RoleName: "Admin", // Admin role to bypass permission checks
|
||||
RoleName: "Admin",
|
||||
Permissions: map[string]bool{"*": true},
|
||||
CachedAt: time.Now(),
|
||||
}
|
||||
@@ -38,21 +32,18 @@ func (m *MockAuthMiddleware) Authenticate(ctx *fiber.Ctx) error {
|
||||
return ctx.Next()
|
||||
}
|
||||
|
||||
// HasPermission is a middleware that allows all permission checks to pass for testing
|
||||
func (m *MockAuthMiddleware) HasPermission(requiredPermission string) fiber.Handler {
|
||||
return func(ctx *fiber.Ctx) error {
|
||||
return ctx.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// AuthRateLimit is a test implementation that allows all requests
|
||||
func (m *MockAuthMiddleware) AuthRateLimit() fiber.Handler {
|
||||
return func(ctx *fiber.Ctx) error {
|
||||
return ctx.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// RequireHTTPS is a test implementation that allows all HTTP requests
|
||||
func (m *MockAuthMiddleware) RequireHTTPS() fiber.Handler {
|
||||
return func(ctx *fiber.Ctx) error {
|
||||
return ctx.Next()
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// MockConfigRepository provides a mock implementation of ConfigRepository
|
||||
type MockConfigRepository struct {
|
||||
configs map[string]*model.Config
|
||||
shouldFailGet bool
|
||||
@@ -21,7 +20,6 @@ func NewMockConfigRepository() *MockConfigRepository {
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateConfig mocks the UpdateConfig method
|
||||
func (m *MockConfigRepository) UpdateConfig(ctx context.Context, config *model.Config) *model.Config {
|
||||
if m.shouldFailUpdate {
|
||||
return nil
|
||||
@@ -36,18 +34,15 @@ func (m *MockConfigRepository) UpdateConfig(ctx context.Context, config *model.C
|
||||
return config
|
||||
}
|
||||
|
||||
// SetShouldFailUpdate configures the mock to fail on UpdateConfig calls
|
||||
func (m *MockConfigRepository) SetShouldFailUpdate(shouldFail bool) {
|
||||
m.shouldFailUpdate = shouldFail
|
||||
}
|
||||
|
||||
// GetConfig retrieves a config by server ID and config file
|
||||
func (m *MockConfigRepository) GetConfig(serverID uuid.UUID, configFile string) *model.Config {
|
||||
key := serverID.String() + "_" + configFile
|
||||
return m.configs[key]
|
||||
}
|
||||
|
||||
// MockServerRepository provides a mock implementation of ServerRepository
|
||||
type MockServerRepository struct {
|
||||
servers map[uuid.UUID]*model.Server
|
||||
shouldFailGet bool
|
||||
@@ -59,7 +54,6 @@ func NewMockServerRepository() *MockServerRepository {
|
||||
}
|
||||
}
|
||||
|
||||
// GetByID mocks the GetByID method
|
||||
func (m *MockServerRepository) GetByID(ctx context.Context, id interface{}) (*model.Server, error) {
|
||||
if m.shouldFailGet {
|
||||
return nil, errors.New("server not found")
|
||||
@@ -88,17 +82,14 @@ func (m *MockServerRepository) GetByID(ctx context.Context, id interface{}) (*mo
|
||||
return server, nil
|
||||
}
|
||||
|
||||
// AddServer adds a server to the mock repository
|
||||
func (m *MockServerRepository) AddServer(server *model.Server) {
|
||||
m.servers[server.ID] = server
|
||||
}
|
||||
|
||||
// SetShouldFailGet configures the mock to fail on GetByID calls
|
||||
func (m *MockServerRepository) SetShouldFailGet(shouldFail bool) {
|
||||
m.shouldFailGet = shouldFail
|
||||
}
|
||||
|
||||
// MockServerService provides a mock implementation of ServerService
|
||||
type MockServerService struct {
|
||||
startRuntimeCalled bool
|
||||
startRuntimeServer *model.Server
|
||||
@@ -108,23 +99,19 @@ func NewMockServerService() *MockServerService {
|
||||
return &MockServerService{}
|
||||
}
|
||||
|
||||
// StartAccServerRuntime mocks the StartAccServerRuntime method
|
||||
func (m *MockServerService) StartAccServerRuntime(server *model.Server) {
|
||||
m.startRuntimeCalled = true
|
||||
m.startRuntimeServer = server
|
||||
}
|
||||
|
||||
// WasStartRuntimeCalled returns whether StartAccServerRuntime was called
|
||||
func (m *MockServerService) WasStartRuntimeCalled() bool {
|
||||
return m.startRuntimeCalled
|
||||
}
|
||||
|
||||
// GetStartRuntimeServer returns the server passed to StartAccServerRuntime
|
||||
func (m *MockServerService) GetStartRuntimeServer() *model.Server {
|
||||
return m.startRuntimeServer
|
||||
}
|
||||
|
||||
// Reset resets the mock state
|
||||
func (m *MockServerService) Reset() {
|
||||
m.startRuntimeCalled = false
|
||||
m.startRuntimeServer = nil
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// MockStateHistoryRepository provides a mock implementation of StateHistoryRepository
|
||||
type MockStateHistoryRepository struct {
|
||||
stateHistories []model.StateHistory
|
||||
shouldFailGet bool
|
||||
@@ -21,7 +20,6 @@ func NewMockStateHistoryRepository() *MockStateHistoryRepository {
|
||||
}
|
||||
}
|
||||
|
||||
// GetAll mocks the GetAll method
|
||||
func (m *MockStateHistoryRepository) GetAll(ctx context.Context, filter *model.StateHistoryFilter) (*[]model.StateHistory, error) {
|
||||
if m.shouldFailGet {
|
||||
return nil, errors.New("failed to get state history")
|
||||
@@ -37,13 +35,11 @@ func (m *MockStateHistoryRepository) GetAll(ctx context.Context, filter *model.S
|
||||
return &filtered, nil
|
||||
}
|
||||
|
||||
// Insert mocks the Insert method
|
||||
func (m *MockStateHistoryRepository) Insert(ctx context.Context, stateHistory *model.StateHistory) error {
|
||||
if m.shouldFailInsert {
|
||||
return errors.New("failed to insert state history")
|
||||
}
|
||||
|
||||
// Simulate BeforeCreate hook
|
||||
if stateHistory.ID == uuid.Nil {
|
||||
stateHistory.ID = uuid.New()
|
||||
}
|
||||
@@ -55,7 +51,6 @@ func (m *MockStateHistoryRepository) Insert(ctx context.Context, stateHistory *m
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetLastSessionID mocks the GetLastSessionID method
|
||||
func (m *MockStateHistoryRepository) GetLastSessionID(ctx context.Context, serverID uuid.UUID) (uuid.UUID, error) {
|
||||
for i := len(m.stateHistories) - 1; i >= 0; i-- {
|
||||
if m.stateHistories[i].ServerID == serverID {
|
||||
@@ -65,7 +60,6 @@ func (m *MockStateHistoryRepository) GetLastSessionID(ctx context.Context, serve
|
||||
return uuid.Nil, nil
|
||||
}
|
||||
|
||||
// Helper methods for filtering
|
||||
func (m *MockStateHistoryRepository) matchesFilter(sh model.StateHistory, filter *model.StateHistoryFilter) bool {
|
||||
if filter == nil {
|
||||
return true
|
||||
@@ -93,7 +87,6 @@ func (m *MockStateHistoryRepository) matchesFilter(sh model.StateHistory, filter
|
||||
return true
|
||||
}
|
||||
|
||||
// Helper methods for testing configuration
|
||||
func (m *MockStateHistoryRepository) SetShouldFailGet(shouldFail bool) {
|
||||
m.shouldFailGet = shouldFail
|
||||
}
|
||||
@@ -102,7 +95,6 @@ func (m *MockStateHistoryRepository) SetShouldFailInsert(shouldFail bool) {
|
||||
m.shouldFailInsert = shouldFail
|
||||
}
|
||||
|
||||
// AddStateHistory adds a state history entry to the mock repository
|
||||
func (m *MockStateHistoryRepository) AddStateHistory(stateHistory model.StateHistory) {
|
||||
if stateHistory.ID == uuid.Nil {
|
||||
stateHistory.ID = uuid.New()
|
||||
@@ -113,22 +105,18 @@ func (m *MockStateHistoryRepository) AddStateHistory(stateHistory model.StateHis
|
||||
m.stateHistories = append(m.stateHistories, stateHistory)
|
||||
}
|
||||
|
||||
// GetCount returns the number of state history entries
|
||||
func (m *MockStateHistoryRepository) GetCount() int {
|
||||
return len(m.stateHistories)
|
||||
}
|
||||
|
||||
// Clear removes all state history entries
|
||||
func (m *MockStateHistoryRepository) Clear() {
|
||||
m.stateHistories = make([]model.StateHistory, 0)
|
||||
}
|
||||
|
||||
// GetSummaryStats calculates peak players, total sessions, and average players for mock data
|
||||
func (m *MockStateHistoryRepository) GetSummaryStats(ctx context.Context, filter *model.StateHistoryFilter) (model.StateHistoryStats, error) {
|
||||
var stats model.StateHistoryStats
|
||||
var filteredEntries []model.StateHistory
|
||||
|
||||
// Filter entries
|
||||
for _, entry := range m.stateHistories {
|
||||
if m.matchesFilter(entry, filter) {
|
||||
filteredEntries = append(filteredEntries, entry)
|
||||
@@ -139,7 +127,6 @@ func (m *MockStateHistoryRepository) GetSummaryStats(ctx context.Context, filter
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// Calculate statistics
|
||||
sessionMap := make(map[string]bool)
|
||||
totalPlayers := 0
|
||||
|
||||
@@ -159,11 +146,9 @@ func (m *MockStateHistoryRepository) GetSummaryStats(ctx context.Context, filter
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// GetTotalPlaytime calculates total playtime in minutes for mock data
|
||||
func (m *MockStateHistoryRepository) GetTotalPlaytime(ctx context.Context, filter *model.StateHistoryFilter) (int, error) {
|
||||
var filteredEntries []model.StateHistory
|
||||
|
||||
// Filter entries
|
||||
for _, entry := range m.stateHistories {
|
||||
if m.matchesFilter(entry, filter) {
|
||||
filteredEntries = append(filteredEntries, entry)
|
||||
@@ -174,7 +159,6 @@ func (m *MockStateHistoryRepository) GetTotalPlaytime(ctx context.Context, filte
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Group by session and calculate durations
|
||||
sessionMap := make(map[string][]model.StateHistory)
|
||||
for _, entry := range filteredEntries {
|
||||
sessionID := entry.SessionID.String()
|
||||
@@ -184,7 +168,6 @@ func (m *MockStateHistoryRepository) GetTotalPlaytime(ctx context.Context, filte
|
||||
totalMinutes := 0
|
||||
for _, sessionEntries := range sessionMap {
|
||||
if len(sessionEntries) > 1 {
|
||||
// Sort by date (simple approach for mock)
|
||||
minTime := sessionEntries[0].DateCreated
|
||||
maxTime := sessionEntries[0].DateCreated
|
||||
hasPlayers := false
|
||||
@@ -211,26 +194,22 @@ func (m *MockStateHistoryRepository) GetTotalPlaytime(ctx context.Context, filte
|
||||
return totalMinutes, nil
|
||||
}
|
||||
|
||||
// GetPlayerCountOverTime returns downsampled player count data for mock
|
||||
func (m *MockStateHistoryRepository) GetPlayerCountOverTime(ctx context.Context, filter *model.StateHistoryFilter) ([]model.PlayerCountPoint, error) {
|
||||
var points []model.PlayerCountPoint
|
||||
var filteredEntries []model.StateHistory
|
||||
|
||||
// Filter entries
|
||||
for _, entry := range m.stateHistories {
|
||||
if m.matchesFilter(entry, filter) {
|
||||
filteredEntries = append(filteredEntries, entry)
|
||||
}
|
||||
}
|
||||
|
||||
// Group by hour (simple mock implementation)
|
||||
hourMap := make(map[string][]int)
|
||||
for _, entry := range filteredEntries {
|
||||
hourKey := entry.DateCreated.Format("2006-01-02 15")
|
||||
hourMap[hourKey] = append(hourMap[hourKey], entry.PlayerCount)
|
||||
}
|
||||
|
||||
// Calculate averages per hour
|
||||
for hourKey, counts := range hourMap {
|
||||
total := 0
|
||||
for _, count := range counts {
|
||||
@@ -247,20 +226,17 @@ func (m *MockStateHistoryRepository) GetPlayerCountOverTime(ctx context.Context,
|
||||
return points, nil
|
||||
}
|
||||
|
||||
// GetSessionTypes counts sessions by type for mock
|
||||
func (m *MockStateHistoryRepository) GetSessionTypes(ctx context.Context, filter *model.StateHistoryFilter) ([]model.SessionCount, error) {
|
||||
var sessionTypes []model.SessionCount
|
||||
var filteredEntries []model.StateHistory
|
||||
|
||||
// Filter entries
|
||||
for _, entry := range m.stateHistories {
|
||||
if m.matchesFilter(entry, filter) {
|
||||
filteredEntries = append(filteredEntries, entry)
|
||||
}
|
||||
}
|
||||
|
||||
// Group by session type
|
||||
sessionMap := make(map[model.TrackSession]map[string]bool) // session -> sessionID -> bool
|
||||
sessionMap := make(map[model.TrackSession]map[string]bool)
|
||||
for _, entry := range filteredEntries {
|
||||
if sessionMap[entry.Session] == nil {
|
||||
sessionMap[entry.Session] = make(map[string]bool)
|
||||
@@ -268,7 +244,6 @@ func (m *MockStateHistoryRepository) GetSessionTypes(ctx context.Context, filter
|
||||
sessionMap[entry.Session][entry.SessionID.String()] = true
|
||||
}
|
||||
|
||||
// Count unique sessions per type
|
||||
for sessionType, sessions := range sessionMap {
|
||||
sessionTypes = append(sessionTypes, model.SessionCount{
|
||||
Name: sessionType,
|
||||
@@ -279,20 +254,17 @@ func (m *MockStateHistoryRepository) GetSessionTypes(ctx context.Context, filter
|
||||
return sessionTypes, nil
|
||||
}
|
||||
|
||||
// GetDailyActivity counts sessions per day for mock
|
||||
func (m *MockStateHistoryRepository) GetDailyActivity(ctx context.Context, filter *model.StateHistoryFilter) ([]model.DailyActivity, error) {
|
||||
var dailyActivity []model.DailyActivity
|
||||
var filteredEntries []model.StateHistory
|
||||
|
||||
// Filter entries
|
||||
for _, entry := range m.stateHistories {
|
||||
if m.matchesFilter(entry, filter) {
|
||||
filteredEntries = append(filteredEntries, entry)
|
||||
}
|
||||
}
|
||||
|
||||
// Group by day
|
||||
dayMap := make(map[string]map[string]bool) // date -> sessionID -> bool
|
||||
dayMap := make(map[string]map[string]bool)
|
||||
for _, entry := range filteredEntries {
|
||||
dateKey := entry.DateCreated.Format("2006-01-02")
|
||||
if dayMap[dateKey] == nil {
|
||||
@@ -301,7 +273,6 @@ func (m *MockStateHistoryRepository) GetDailyActivity(ctx context.Context, filte
|
||||
dayMap[dateKey][entry.SessionID.String()] = true
|
||||
}
|
||||
|
||||
// Count unique sessions per day
|
||||
for date, sessions := range dayMap {
|
||||
dailyActivity = append(dailyActivity, model.DailyActivity{
|
||||
Date: date,
|
||||
@@ -312,26 +283,22 @@ func (m *MockStateHistoryRepository) GetDailyActivity(ctx context.Context, filte
|
||||
return dailyActivity, nil
|
||||
}
|
||||
|
||||
// GetRecentSessions retrieves recent sessions for mock
|
||||
func (m *MockStateHistoryRepository) GetRecentSessions(ctx context.Context, filter *model.StateHistoryFilter) ([]model.RecentSession, error) {
|
||||
var recentSessions []model.RecentSession
|
||||
var filteredEntries []model.StateHistory
|
||||
|
||||
// Filter entries
|
||||
for _, entry := range m.stateHistories {
|
||||
if m.matchesFilter(entry, filter) {
|
||||
filteredEntries = append(filteredEntries, entry)
|
||||
}
|
||||
}
|
||||
|
||||
// Group by session
|
||||
sessionMap := make(map[string][]model.StateHistory)
|
||||
for _, entry := range filteredEntries {
|
||||
sessionID := entry.SessionID.String()
|
||||
sessionMap[sessionID] = append(sessionMap[sessionID], entry)
|
||||
}
|
||||
|
||||
// Create recent sessions (limit to 10)
|
||||
count := 0
|
||||
for _, entries := range sessionMap {
|
||||
if count >= 10 {
|
||||
@@ -339,7 +306,6 @@ func (m *MockStateHistoryRepository) GetRecentSessions(ctx context.Context, filt
|
||||
}
|
||||
|
||||
if len(entries) > 0 {
|
||||
// Find min/max dates and max players
|
||||
minDate := entries[0].DateCreated
|
||||
maxDate := entries[0].DateCreated
|
||||
maxPlayers := 0
|
||||
@@ -356,7 +322,6 @@ func (m *MockStateHistoryRepository) GetRecentSessions(ctx context.Context, filt
|
||||
}
|
||||
}
|
||||
|
||||
// Only include sessions with players
|
||||
if maxPlayers > 0 {
|
||||
duration := int(maxDate.Sub(minDate).Minutes())
|
||||
recentSessions = append(recentSessions, model.RecentSession{
|
||||
|
||||
@@ -24,14 +24,12 @@ import (
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
// TestHelper provides utilities for testing
|
||||
type TestHelper struct {
|
||||
DB *gorm.DB
|
||||
TempDir string
|
||||
TestData *TestData
|
||||
}
|
||||
|
||||
// TestData contains common test data structures
|
||||
type TestData struct {
|
||||
ServerID uuid.UUID
|
||||
Server *model.Server
|
||||
@@ -39,37 +37,29 @@ type TestData struct {
|
||||
SampleConfig *model.Configuration
|
||||
}
|
||||
|
||||
// SetTestEnv sets the required environment variables for tests
|
||||
func SetTestEnv() {
|
||||
// Set required environment variables for testing
|
||||
os.Setenv("APP_SECRET", "test-secret-key-for-testing-123456")
|
||||
os.Setenv("APP_SECRET_CODE", "test-code-for-testing-123456789012")
|
||||
os.Setenv("ENCRYPTION_KEY", "12345678901234567890123456789012")
|
||||
os.Setenv("JWT_SECRET", "test-jwt-secret-key-for-testing-123456789012345678901234567890")
|
||||
os.Setenv("ACCESS_KEY", "test-access-key-for-testing")
|
||||
// Set test-specific environment variables
|
||||
os.Setenv("TESTING_ENV", "true") // Used to bypass
|
||||
os.Setenv("TESTING_ENV", "true")
|
||||
|
||||
configs.Init()
|
||||
}
|
||||
|
||||
// NewTestHelper creates a new test helper with in-memory database
|
||||
func NewTestHelper(t *testing.T) *TestHelper {
|
||||
// Set required environment variables
|
||||
SetTestEnv()
|
||||
|
||||
// Create temporary directory for test files
|
||||
tempDir := t.TempDir()
|
||||
|
||||
// Create in-memory SQLite database for testing
|
||||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logger.Silent), // Suppress SQL logs in tests
|
||||
Logger: logger.Default.LogMode(logger.Silent),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to connect to test database: %v", err)
|
||||
}
|
||||
|
||||
// Auto-migrate the schema
|
||||
err = db.AutoMigrate(
|
||||
&model.Server{},
|
||||
&model.Config{},
|
||||
@@ -79,7 +69,6 @@ func NewTestHelper(t *testing.T) *TestHelper {
|
||||
&model.StateHistory{},
|
||||
)
|
||||
|
||||
// Explicitly ensure tables exist with correct structure
|
||||
if !db.Migrator().HasTable(&model.StateHistory{}) {
|
||||
err = db.Migrator().CreateTable(&model.StateHistory{})
|
||||
if err != nil {
|
||||
@@ -90,7 +79,6 @@ func NewTestHelper(t *testing.T) *TestHelper {
|
||||
t.Fatalf("Failed to migrate test database: %v", err)
|
||||
}
|
||||
|
||||
// Create test data
|
||||
testData := createTestData(t, tempDir)
|
||||
|
||||
return &TestHelper{
|
||||
@@ -100,11 +88,9 @@ func NewTestHelper(t *testing.T) *TestHelper {
|
||||
}
|
||||
}
|
||||
|
||||
// createTestData creates common test data structures
|
||||
func createTestData(t *testing.T, tempDir string) *TestData {
|
||||
serverID := uuid.New()
|
||||
|
||||
// Create sample server
|
||||
server := &model.Server{
|
||||
ID: serverID,
|
||||
Name: "Test Server",
|
||||
@@ -115,13 +101,11 @@ func createTestData(t *testing.T, tempDir string) *TestData {
|
||||
FromSteamCMD: false,
|
||||
}
|
||||
|
||||
// Create server directory
|
||||
serverConfigDir := filepath.Join(tempDir, "server", "cfg")
|
||||
if err := os.MkdirAll(serverConfigDir, 0755); err != nil {
|
||||
t.Fatalf("Failed to create server config directory: %v", err)
|
||||
}
|
||||
|
||||
// Sample configuration files content
|
||||
configFiles := map[string]string{
|
||||
"configuration.json": `{
|
||||
"udpPort": "9231",
|
||||
@@ -212,7 +196,6 @@ func createTestData(t *testing.T, tempDir string) *TestData {
|
||||
}`,
|
||||
}
|
||||
|
||||
// Sample configuration struct
|
||||
sampleConfig := &model.Configuration{
|
||||
UdpPort: model.IntString(9231),
|
||||
TcpPort: model.IntString(9232),
|
||||
@@ -230,14 +213,12 @@ func createTestData(t *testing.T, tempDir string) *TestData {
|
||||
}
|
||||
}
|
||||
|
||||
// CreateTestConfigFiles creates actual config files in the test directory
|
||||
func (th *TestHelper) CreateTestConfigFiles() error {
|
||||
serverConfigDir := filepath.Join(th.TestData.Server.Path, "cfg")
|
||||
|
||||
for filename, content := range th.TestData.ConfigFiles {
|
||||
filePath := filepath.Join(serverConfigDir, filename)
|
||||
|
||||
// Encode content to UTF-16 LE BOM format as expected by the application
|
||||
utf16Content, err := EncodeUTF16LEBOM([]byte(content))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -251,7 +232,6 @@ func (th *TestHelper) CreateTestConfigFiles() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateMalformedConfigFile creates a config file with invalid JSON
|
||||
func (th *TestHelper) CreateMalformedConfigFile(filename string) error {
|
||||
serverConfigDir := filepath.Join(th.TestData.Server.Path, "cfg")
|
||||
filePath := filepath.Join(serverConfigDir, filename)
|
||||
@@ -259,67 +239,51 @@ func (th *TestHelper) CreateMalformedConfigFile(filename string) error {
|
||||
malformedJSON := `{
|
||||
"udpPort": "9231",
|
||||
"tcpPort": "9232"
|
||||
"maxConnections": "30" // Missing comma - invalid JSON
|
||||
"maxConnections": "30"
|
||||
}`
|
||||
|
||||
return os.WriteFile(filePath, []byte(malformedJSON), 0644)
|
||||
}
|
||||
|
||||
// RemoveConfigFile removes a config file to simulate missing file scenarios
|
||||
func (th *TestHelper) RemoveConfigFile(filename string) error {
|
||||
serverConfigDir := filepath.Join(th.TestData.Server.Path, "cfg")
|
||||
filePath := filepath.Join(serverConfigDir, filename)
|
||||
return os.Remove(filePath)
|
||||
}
|
||||
|
||||
// InsertTestServer inserts the test server into the database
|
||||
func (th *TestHelper) InsertTestServer() error {
|
||||
return th.DB.Create(th.TestData.Server).Error
|
||||
}
|
||||
|
||||
// CreateContext creates a test context
|
||||
func (th *TestHelper) CreateContext() context.Context {
|
||||
return context.Background()
|
||||
}
|
||||
|
||||
// CreateFiberCtx creates a fiber.Ctx for testing
|
||||
func (th *TestHelper) CreateFiberCtx() *fiber.Ctx {
|
||||
// Create app and request for fiber context
|
||||
app := fiber.New()
|
||||
// Create a dummy request that doesn't depend on external http objects
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
// Create the fiber context from real request/response
|
||||
ctx := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||
// Store the original request for release later
|
||||
ctx.Locals("original-request", req)
|
||||
// Return the context which can be safely used in tests
|
||||
return ctx
|
||||
}
|
||||
|
||||
// ReleaseFiberCtx properly releases a fiber context created with CreateFiberCtx
|
||||
func (th *TestHelper) ReleaseFiberCtx(app *fiber.App, ctx *fiber.Ctx) {
|
||||
if app != nil && ctx != nil {
|
||||
app.ReleaseCtx(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup performs cleanup operations after tests
|
||||
func (th *TestHelper) Cleanup() {
|
||||
// Close database connection
|
||||
if sqlDB, err := th.DB.DB(); err == nil {
|
||||
sqlDB.Close()
|
||||
}
|
||||
|
||||
// Temporary directory is automatically cleaned up by t.TempDir()
|
||||
}
|
||||
|
||||
// LoadTestEnvFile loads environment variables from a .env file for testing
|
||||
func LoadTestEnvFile() error {
|
||||
// Try to load from .env file
|
||||
return godotenv.Load()
|
||||
}
|
||||
|
||||
// AssertNoError is a helper function to check for errors in tests
|
||||
func AssertNoError(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
if err != nil {
|
||||
@@ -327,7 +291,6 @@ func AssertNoError(t *testing.T, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
// AssertError is a helper function to check for expected errors
|
||||
func AssertError(t *testing.T, err error, expectedMsg string) {
|
||||
t.Helper()
|
||||
if err == nil {
|
||||
@@ -338,7 +301,6 @@ func AssertError(t *testing.T, err error, expectedMsg string) {
|
||||
}
|
||||
}
|
||||
|
||||
// AssertEqual checks if two values are equal
|
||||
func AssertEqual(t *testing.T, expected, actual interface{}) {
|
||||
t.Helper()
|
||||
if expected != actual {
|
||||
@@ -346,7 +308,6 @@ func AssertEqual(t *testing.T, expected, actual interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// AssertNotNil checks if a value is not nil
|
||||
func AssertNotNil(t *testing.T, value interface{}) {
|
||||
t.Helper()
|
||||
if value == nil {
|
||||
@@ -354,12 +315,9 @@ func AssertNotNil(t *testing.T, value interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// AssertNil checks if a value is nil
|
||||
func AssertNil(t *testing.T, value interface{}) {
|
||||
t.Helper()
|
||||
if value != nil {
|
||||
// Special handling for interface values that contain nil but aren't nil themselves
|
||||
// For example, (*jwt.Claims)(nil) is not equal to nil, but it contains nil
|
||||
switch v := value.(type) {
|
||||
case *interface{}:
|
||||
if v == nil || *v == nil {
|
||||
@@ -374,13 +332,11 @@ func AssertNil(t *testing.T, value interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// EncodeUTF16LEBOM encodes UTF-8 bytes to UTF-16 LE BOM format
|
||||
func EncodeUTF16LEBOM(input []byte) ([]byte, error) {
|
||||
encoder := unicode.UTF16(unicode.LittleEndian, unicode.UseBOM)
|
||||
return transformBytes(encoder.NewEncoder(), input)
|
||||
}
|
||||
|
||||
// transformBytes applies a transform to input bytes
|
||||
func transformBytes(t transform.Transformer, input []byte) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
w := transform.NewWriter(&buf, t)
|
||||
@@ -396,7 +352,6 @@ func transformBytes(t transform.Transformer, input []byte) ([]byte, error) {
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// ErrorForTesting creates an error for testing purposes
|
||||
func ErrorForTesting(message string) error {
|
||||
return errors.New(message)
|
||||
}
|
||||
|
||||
9
tests/testdata/state_history_data.go
vendored
9
tests/testdata/state_history_data.go
vendored
@@ -7,13 +7,11 @@ import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// StateHistoryTestData provides simple test data generators
|
||||
type StateHistoryTestData struct {
|
||||
ServerID uuid.UUID
|
||||
BaseTime time.Time
|
||||
}
|
||||
|
||||
// NewStateHistoryTestData creates a new test data generator
|
||||
func NewStateHistoryTestData(serverID uuid.UUID) *StateHistoryTestData {
|
||||
return &StateHistoryTestData{
|
||||
ServerID: serverID,
|
||||
@@ -21,7 +19,6 @@ func NewStateHistoryTestData(serverID uuid.UUID) *StateHistoryTestData {
|
||||
}
|
||||
}
|
||||
|
||||
// CreateStateHistory creates a basic state history entry
|
||||
func (td *StateHistoryTestData) CreateStateHistory(session model.TrackSession, track string, playerCount int, sessionID uuid.UUID) model.StateHistory {
|
||||
return model.StateHistory{
|
||||
ID: uuid.New(),
|
||||
@@ -36,7 +33,6 @@ func (td *StateHistoryTestData) CreateStateHistory(session model.TrackSession, t
|
||||
}
|
||||
}
|
||||
|
||||
// CreateMultipleEntries creates multiple state history entries for the same session
|
||||
func (td *StateHistoryTestData) CreateMultipleEntries(session model.TrackSession, track string, playerCounts []int) []model.StateHistory {
|
||||
sessionID := uuid.New()
|
||||
var entries []model.StateHistory
|
||||
@@ -59,7 +55,6 @@ func (td *StateHistoryTestData) CreateMultipleEntries(session model.TrackSession
|
||||
return entries
|
||||
}
|
||||
|
||||
// CreateBasicFilter creates a basic filter for testing
|
||||
func CreateBasicFilter(serverID string) *model.StateHistoryFilter {
|
||||
return &model.StateHistoryFilter{
|
||||
ServerBasedFilter: model.ServerBasedFilter{
|
||||
@@ -68,7 +63,6 @@ func CreateBasicFilter(serverID string) *model.StateHistoryFilter {
|
||||
}
|
||||
}
|
||||
|
||||
// CreateFilterWithSession creates a filter with session type
|
||||
func CreateFilterWithSession(serverID string, session model.TrackSession) *model.StateHistoryFilter {
|
||||
return &model.StateHistoryFilter{
|
||||
ServerBasedFilter: model.ServerBasedFilter{
|
||||
@@ -78,7 +72,6 @@ func CreateFilterWithSession(serverID string, session model.TrackSession) *model
|
||||
}
|
||||
}
|
||||
|
||||
// LogLines contains sample ACC server log lines for testing
|
||||
var SampleLogLines = []string{
|
||||
"[2024-01-15 14:30:25.123] Session changed: NONE -> PRACTICE",
|
||||
"[2024-01-15 14:30:30.456] 1 client(s) online",
|
||||
@@ -95,7 +88,6 @@ var SampleLogLines = []string{
|
||||
"[2024-01-15 15:00:05.123] Session changed: RACE -> NONE",
|
||||
}
|
||||
|
||||
// ExpectedSessionChanges represents the expected session changes from parsing the sample log lines
|
||||
var ExpectedSessionChanges = []struct {
|
||||
From model.TrackSession
|
||||
To model.TrackSession
|
||||
@@ -106,5 +98,4 @@ var ExpectedSessionChanges = []struct {
|
||||
{model.SessionRace, model.SessionUnknown},
|
||||
}
|
||||
|
||||
// ExpectedPlayerCounts represents the expected player counts from parsing the sample log lines
|
||||
var ExpectedPlayerCounts = []int{1, 3, 5, 8, 12, 15, 14, 0}
|
||||
|
||||
@@ -14,12 +14,10 @@ import (
|
||||
)
|
||||
|
||||
func TestController_JSONParsing_Success(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
// Test basic JSON parsing functionality
|
||||
app := fiber.New()
|
||||
|
||||
app.Post("/test", func(c *fiber.Ctx) error {
|
||||
@@ -30,7 +28,6 @@ func TestController_JSONParsing_Success(t *testing.T) {
|
||||
return c.JSON(data)
|
||||
})
|
||||
|
||||
// Prepare test data
|
||||
testData := map[string]interface{}{
|
||||
"name": "test",
|
||||
"value": 123,
|
||||
@@ -38,34 +35,28 @@ func TestController_JSONParsing_Success(t *testing.T) {
|
||||
bodyBytes, err := json.Marshal(testData)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Create request
|
||||
req := httptest.NewRequest("POST", "/test", bytes.NewReader(bodyBytes))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// Execute request
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
tests.AssertEqual(t, 200, resp.StatusCode)
|
||||
|
||||
// Parse response
|
||||
var response map[string]interface{}
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
tests.AssertNoError(t, err)
|
||||
err = json.Unmarshal(body, &response)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify response
|
||||
tests.AssertEqual(t, "test", response["name"])
|
||||
tests.AssertEqual(t, float64(123), response["value"]) // JSON numbers are float64
|
||||
tests.AssertEqual(t, float64(123), response["value"])
|
||||
}
|
||||
|
||||
func TestController_JSONParsing_InvalidJSON(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
// Test handling of invalid JSON
|
||||
app := fiber.New()
|
||||
|
||||
app.Post("/test", func(c *fiber.Ctx) error {
|
||||
@@ -76,39 +67,31 @@ func TestController_JSONParsing_InvalidJSON(t *testing.T) {
|
||||
return c.JSON(data)
|
||||
})
|
||||
|
||||
// Create request with invalid JSON
|
||||
req := httptest.NewRequest("POST", "/test", bytes.NewReader([]byte("invalid json")))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// Execute request
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
tests.AssertEqual(t, 400, resp.StatusCode)
|
||||
|
||||
// Parse error response
|
||||
var response map[string]interface{}
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
tests.AssertNoError(t, err)
|
||||
err = json.Unmarshal(body, &response)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify error response
|
||||
tests.AssertEqual(t, "Invalid JSON", response["error"])
|
||||
}
|
||||
|
||||
func TestController_UUIDValidation_Success(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
// Test UUID parameter validation
|
||||
app := fiber.New()
|
||||
|
||||
app.Get("/test/:id", func(c *fiber.Ctx) error {
|
||||
id := c.Params("id")
|
||||
|
||||
// Validate UUID
|
||||
if _, err := uuid.Parse(id); err != nil {
|
||||
return c.Status(400).JSON(fiber.Map{"error": "Invalid UUID"})
|
||||
}
|
||||
@@ -116,40 +99,33 @@ func TestController_UUIDValidation_Success(t *testing.T) {
|
||||
return c.JSON(fiber.Map{"id": id, "valid": true})
|
||||
})
|
||||
|
||||
// Create request with valid UUID
|
||||
validUUID := uuid.New().String()
|
||||
req := httptest.NewRequest("GET", "/test/"+validUUID, nil)
|
||||
|
||||
// Execute request
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
tests.AssertEqual(t, 200, resp.StatusCode)
|
||||
|
||||
// Parse response
|
||||
var response map[string]interface{}
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
tests.AssertNoError(t, err)
|
||||
err = json.Unmarshal(body, &response)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify response
|
||||
tests.AssertEqual(t, validUUID, response["id"])
|
||||
tests.AssertEqual(t, true, response["valid"])
|
||||
}
|
||||
|
||||
func TestController_UUIDValidation_InvalidUUID(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
// Test handling of invalid UUID
|
||||
app := fiber.New()
|
||||
|
||||
app.Get("/test/:id", func(c *fiber.Ctx) error {
|
||||
id := c.Params("id")
|
||||
|
||||
// Validate UUID
|
||||
if _, err := uuid.Parse(id); err != nil {
|
||||
return c.Status(400).JSON(fiber.Map{"error": "Invalid UUID"})
|
||||
}
|
||||
@@ -157,32 +133,26 @@ func TestController_UUIDValidation_InvalidUUID(t *testing.T) {
|
||||
return c.JSON(fiber.Map{"id": id, "valid": true})
|
||||
})
|
||||
|
||||
// Create request with invalid UUID
|
||||
req := httptest.NewRequest("GET", "/test/invalid-uuid", nil)
|
||||
|
||||
// Execute request
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
tests.AssertEqual(t, 400, resp.StatusCode)
|
||||
|
||||
// Parse error response
|
||||
var response map[string]interface{}
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
tests.AssertNoError(t, err)
|
||||
err = json.Unmarshal(body, &response)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify error response
|
||||
tests.AssertEqual(t, "Invalid UUID", response["error"])
|
||||
}
|
||||
|
||||
func TestController_QueryParameters_Success(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
// Test query parameter handling
|
||||
app := fiber.New()
|
||||
|
||||
app.Get("/test", func(c *fiber.Ctx) error {
|
||||
@@ -197,34 +167,28 @@ func TestController_QueryParameters_Success(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
// Create request with query parameters
|
||||
req := httptest.NewRequest("GET", "/test?restart=true&override=false&format=xml", nil)
|
||||
|
||||
// Execute request
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
tests.AssertEqual(t, 200, resp.StatusCode)
|
||||
|
||||
// Parse response
|
||||
var response map[string]interface{}
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
tests.AssertNoError(t, err)
|
||||
err = json.Unmarshal(body, &response)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify response
|
||||
tests.AssertEqual(t, true, response["restart"])
|
||||
tests.AssertEqual(t, false, response["override"])
|
||||
tests.AssertEqual(t, "xml", response["format"])
|
||||
}
|
||||
|
||||
func TestController_HTTPMethods_Success(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
// Test different HTTP methods
|
||||
app := fiber.New()
|
||||
|
||||
var getCalled, postCalled, putCalled, deleteCalled bool
|
||||
@@ -249,28 +213,24 @@ func TestController_HTTPMethods_Success(t *testing.T) {
|
||||
return c.JSON(fiber.Map{"method": "DELETE"})
|
||||
})
|
||||
|
||||
// Test GET
|
||||
req := httptest.NewRequest("GET", "/test", nil)
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
tests.AssertEqual(t, 200, resp.StatusCode)
|
||||
tests.AssertEqual(t, true, getCalled)
|
||||
|
||||
// Test POST
|
||||
req = httptest.NewRequest("POST", "/test", nil)
|
||||
resp, err = app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
tests.AssertEqual(t, 200, resp.StatusCode)
|
||||
tests.AssertEqual(t, true, postCalled)
|
||||
|
||||
// Test PUT
|
||||
req = httptest.NewRequest("PUT", "/test", nil)
|
||||
resp, err = app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
tests.AssertEqual(t, 200, resp.StatusCode)
|
||||
tests.AssertEqual(t, true, putCalled)
|
||||
|
||||
// Test DELETE
|
||||
req = httptest.NewRequest("DELETE", "/test", nil)
|
||||
resp, err = app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
@@ -279,12 +239,10 @@ func TestController_HTTPMethods_Success(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestController_ErrorHandling_StatusCodes(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
// Test different error status codes
|
||||
app := fiber.New()
|
||||
|
||||
app.Get("/400", func(c *fiber.Ctx) error {
|
||||
@@ -307,7 +265,6 @@ func TestController_ErrorHandling_StatusCodes(t *testing.T) {
|
||||
return c.Status(500).JSON(fiber.Map{"error": "Internal Server Error"})
|
||||
})
|
||||
|
||||
// Test different status codes
|
||||
testCases := []struct {
|
||||
path string
|
||||
code int
|
||||
@@ -328,12 +285,10 @@ func TestController_ErrorHandling_StatusCodes(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestController_ConfigurationModel_JSONSerialization(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
// Test Configuration model JSON serialization
|
||||
app := fiber.New()
|
||||
|
||||
app.Get("/config", func(c *fiber.Ctx) error {
|
||||
@@ -348,22 +303,18 @@ func TestController_ConfigurationModel_JSONSerialization(t *testing.T) {
|
||||
return c.JSON(config)
|
||||
})
|
||||
|
||||
// Create request
|
||||
req := httptest.NewRequest("GET", "/config", nil)
|
||||
|
||||
// Execute request
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
tests.AssertEqual(t, 200, resp.StatusCode)
|
||||
|
||||
// Parse response
|
||||
var response model.Configuration
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
tests.AssertNoError(t, err)
|
||||
err = json.Unmarshal(body, &response)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify response
|
||||
tests.AssertEqual(t, model.IntString(9231), response.UdpPort)
|
||||
tests.AssertEqual(t, model.IntString(9232), response.TcpPort)
|
||||
tests.AssertEqual(t, model.IntString(30), response.MaxConnections)
|
||||
@@ -373,73 +324,61 @@ func TestController_ConfigurationModel_JSONSerialization(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestController_UserModel_JSONSerialization(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
// Test User model JSON serialization (password should be hidden)
|
||||
app := fiber.New()
|
||||
|
||||
app.Get("/user", func(c *fiber.Ctx) error {
|
||||
user := &model.User{
|
||||
ID: uuid.New(),
|
||||
Username: "testuser",
|
||||
Password: "secret-password", // Should not appear in JSON
|
||||
Password: "secret-password",
|
||||
RoleID: uuid.New(),
|
||||
}
|
||||
return c.JSON(user)
|
||||
})
|
||||
|
||||
// Create request
|
||||
req := httptest.NewRequest("GET", "/user", nil)
|
||||
|
||||
// Execute request
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
tests.AssertEqual(t, 200, resp.StatusCode)
|
||||
|
||||
// Parse response as raw JSON to check password is excluded
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify password field is not in JSON
|
||||
if bytes.Contains(body, []byte("password")) || bytes.Contains(body, []byte("secret-password")) {
|
||||
t.Fatal("Password should not be included in JSON response")
|
||||
}
|
||||
|
||||
// Verify other fields are present
|
||||
if !bytes.Contains(body, []byte("username")) || !bytes.Contains(body, []byte("testuser")) {
|
||||
t.Fatal("Username should be included in JSON response")
|
||||
}
|
||||
}
|
||||
|
||||
func TestController_MiddlewareChaining_Success(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
// Test middleware chaining
|
||||
app := fiber.New()
|
||||
|
||||
var middleware1Called, middleware2Called, handlerCalled bool
|
||||
|
||||
// Middleware 1
|
||||
middleware1 := func(c *fiber.Ctx) error {
|
||||
middleware1Called = true
|
||||
c.Locals("middleware1", "executed")
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
// Middleware 2
|
||||
middleware2 := func(c *fiber.Ctx) error {
|
||||
middleware2Called = true
|
||||
c.Locals("middleware2", "executed")
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
// Handler
|
||||
handler := func(c *fiber.Ctx) error {
|
||||
handlerCalled = true
|
||||
return c.JSON(fiber.Map{
|
||||
@@ -451,27 +390,22 @@ func TestController_MiddlewareChaining_Success(t *testing.T) {
|
||||
|
||||
app.Get("/test", middleware1, middleware2, handler)
|
||||
|
||||
// Create request
|
||||
req := httptest.NewRequest("GET", "/test", nil)
|
||||
|
||||
// Execute request
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
tests.AssertEqual(t, 200, resp.StatusCode)
|
||||
|
||||
// Verify all were called
|
||||
tests.AssertEqual(t, true, middleware1Called)
|
||||
tests.AssertEqual(t, true, middleware2Called)
|
||||
tests.AssertEqual(t, true, handlerCalled)
|
||||
|
||||
// Parse response
|
||||
var response map[string]interface{}
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
tests.AssertNoError(t, err)
|
||||
err = json.Unmarshal(body, &response)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify middleware values were passed
|
||||
tests.AssertEqual(t, "executed", response["middleware1"])
|
||||
tests.AssertEqual(t, "executed", response["middleware2"])
|
||||
tests.AssertEqual(t, "executed", response["handler"])
|
||||
|
||||
@@ -11,27 +11,20 @@ import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// MockMiddleware simulates authentication for testing purposes
|
||||
type MockMiddleware struct{}
|
||||
|
||||
// GetTestAuthMiddleware returns a mock auth middleware that can be used in place of the real one
|
||||
// This works because we're adding real authentication tokens to requests
|
||||
func GetTestAuthMiddleware(ms *service.MembershipService, cache *cache.InMemoryCache) *middleware.AuthMiddleware {
|
||||
// Use environment JWT secrets for consistency with token generation
|
||||
jwtSecret := os.Getenv("JWT_SECRET")
|
||||
if jwtSecret == "" {
|
||||
jwtSecret = "test-secret-that-is-at-least-32-bytes-long-for-security"
|
||||
}
|
||||
|
||||
|
||||
jwtHandler := jwt.NewJWTHandler(jwtSecret)
|
||||
openJWTHandler := jwt.NewOpenJWTHandler(jwtSecret) // Use same secret for test consistency
|
||||
|
||||
// Cast our mock to the real type for testing
|
||||
// This is a type-unsafe cast but works for testing because we're using real JWT tokens
|
||||
openJWTHandler := jwt.NewOpenJWTHandler(jwtSecret)
|
||||
|
||||
return middleware.NewAuthMiddleware(ms, cache, jwtHandler, openJWTHandler)
|
||||
}
|
||||
|
||||
// AddAuthToRequest adds a valid authentication token to a test request
|
||||
func AddAuthToRequest(req *fiber.Ctx) {
|
||||
token := tests.MustGenerateTestToken()
|
||||
req.Request().Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
@@ -23,13 +23,11 @@ import (
|
||||
)
|
||||
|
||||
func TestStateHistoryController_GetAll_Success(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
app := fiber.New()
|
||||
// No need for DisableAuthentication, we'll use real auth tokens
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
stateHistoryService := service.NewStateHistoryService(repo)
|
||||
|
||||
@@ -44,33 +42,26 @@ func TestStateHistoryController_GetAll_Success(t *testing.T) {
|
||||
|
||||
inMemCache := cache.NewInMemoryCache()
|
||||
|
||||
// Insert test data
|
||||
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)
|
||||
|
||||
// Setup routes
|
||||
routeGroups := &common.RouteGroups{
|
||||
StateHistory: app.Group("/api/v1/state-history"),
|
||||
}
|
||||
|
||||
// Use a test auth middleware that works with the DisableAuthentication
|
||||
controller.NewStateHistoryController(stateHistoryService, routeGroups, GetTestAuthMiddleware(membershipService, inMemCache))
|
||||
|
||||
// Create request with authentication
|
||||
req := httptest.NewRequest("GET", fmt.Sprintf("/api/v1/state-history?id=%s", helper.TestData.ServerID.String()), nil)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", "Bearer "+tests.MustGenerateTestToken())
|
||||
|
||||
// Execute request
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify response
|
||||
tests.AssertEqual(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
// Parse response body
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
@@ -83,13 +74,11 @@ func TestStateHistoryController_GetAll_Success(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStateHistoryController_GetAll_WithSessionFilter(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
app := fiber.New()
|
||||
// Using real JWT auth with tokens
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
stateHistoryService := service.NewStateHistoryService(repo)
|
||||
|
||||
@@ -104,7 +93,6 @@ func TestStateHistoryController_GetAll_WithSessionFilter(t *testing.T) {
|
||||
|
||||
inMemCache := cache.NewInMemoryCache()
|
||||
|
||||
// Insert test data with different sessions
|
||||
testData := testdata.NewStateHistoryTestData(helper.TestData.ServerID)
|
||||
|
||||
practiceHistory := testData.CreateStateHistory(model.SessionPractice, "spa", 5, uuid.New())
|
||||
@@ -115,27 +103,21 @@ func TestStateHistoryController_GetAll_WithSessionFilter(t *testing.T) {
|
||||
err = repo.Insert(helper.CreateContext(), &raceHistory)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Setup routes
|
||||
routeGroups := &common.RouteGroups{
|
||||
StateHistory: app.Group("/api/v1/state-history"),
|
||||
}
|
||||
|
||||
// Use a test auth middleware that works with the DisableAuthentication
|
||||
controller.NewStateHistoryController(stateHistoryService, routeGroups, GetTestAuthMiddleware(membershipService, inMemCache))
|
||||
|
||||
// Create request with session filter and authentication
|
||||
req := httptest.NewRequest("GET", fmt.Sprintf("/api/v1/state-history?id=%s&session=R", helper.TestData.ServerID.String()), nil)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", "Bearer "+tests.MustGenerateTestToken())
|
||||
|
||||
// Execute request
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify response
|
||||
tests.AssertEqual(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
// Parse response body
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
@@ -148,13 +130,11 @@ func TestStateHistoryController_GetAll_WithSessionFilter(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStateHistoryController_GetAll_EmptyResult(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
app := fiber.New()
|
||||
// Using real JWT auth with tokens
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
stateHistoryService := service.NewStateHistoryService(repo)
|
||||
|
||||
@@ -169,38 +149,30 @@ func TestStateHistoryController_GetAll_EmptyResult(t *testing.T) {
|
||||
|
||||
inMemCache := cache.NewInMemoryCache()
|
||||
|
||||
// Setup routes
|
||||
routeGroups := &common.RouteGroups{
|
||||
StateHistory: app.Group("/api/v1/state-history"),
|
||||
}
|
||||
|
||||
// Use a test auth middleware that works with the DisableAuthentication
|
||||
controller.NewStateHistoryController(stateHistoryService, routeGroups, GetTestAuthMiddleware(membershipService, inMemCache))
|
||||
|
||||
// Create request with no data and authentication
|
||||
req := httptest.NewRequest("GET", fmt.Sprintf("/api/v1/state-history?id=%s", helper.TestData.ServerID.String()), nil)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", "Bearer "+tests.MustGenerateTestToken())
|
||||
|
||||
// Execute request
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify empty response
|
||||
tests.AssertEqual(t, http.StatusOK, resp.StatusCode)
|
||||
}
|
||||
|
||||
func TestStateHistoryController_GetStatistics_Success(t *testing.T) {
|
||||
// Skip this test as it requires more complex setup
|
||||
t.Skip("Skipping test due to UUID validation issues")
|
||||
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
app := fiber.New()
|
||||
// Using real JWT auth with tokens
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
stateHistoryService := service.NewStateHistoryService(repo)
|
||||
|
||||
@@ -215,10 +187,8 @@ func TestStateHistoryController_GetStatistics_Success(t *testing.T) {
|
||||
|
||||
inMemCache := cache.NewInMemoryCache()
|
||||
|
||||
// Insert test data with multiple entries for statistics
|
||||
testData := testdata.NewStateHistoryTestData(helper.TestData.ServerID)
|
||||
|
||||
// Create entries with varying player counts
|
||||
playerCounts := []int{5, 10, 15, 20, 25}
|
||||
entries := testData.CreateMultipleEntries(model.SessionRace, "spa", playerCounts)
|
||||
|
||||
@@ -227,33 +197,26 @@ func TestStateHistoryController_GetStatistics_Success(t *testing.T) {
|
||||
tests.AssertNoError(t, err)
|
||||
}
|
||||
|
||||
// Setup routes
|
||||
routeGroups := &common.RouteGroups{
|
||||
StateHistory: app.Group("/api/v1/state-history"),
|
||||
}
|
||||
|
||||
// Use a test auth middleware that works with the DisableAuthentication
|
||||
controller.NewStateHistoryController(stateHistoryService, routeGroups, GetTestAuthMiddleware(membershipService, inMemCache))
|
||||
|
||||
// Create request with valid serverID UUID
|
||||
validServerID := helper.TestData.ServerID.String()
|
||||
if validServerID == "" {
|
||||
validServerID = uuid.New().String() // Generate a new valid UUID if needed
|
||||
validServerID = uuid.New().String()
|
||||
}
|
||||
req := httptest.NewRequest("GET", fmt.Sprintf("/api/v1/state-history/statistics?id=%s", validServerID), nil)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// Add Authorization header for testing
|
||||
req.Header.Set("Authorization", "Bearer "+tests.MustGenerateTestToken())
|
||||
|
||||
// Execute request
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify response
|
||||
tests.AssertEqual(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
// Parse response body
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
@@ -261,7 +224,6 @@ func TestStateHistoryController_GetStatistics_Success(t *testing.T) {
|
||||
err = json.Unmarshal(body, &stats)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify statistics structure exists (actual calculation is tested in service layer)
|
||||
if stats.PeakPlayers < 0 {
|
||||
t.Error("Expected non-negative peak players")
|
||||
}
|
||||
@@ -274,16 +236,13 @@ func TestStateHistoryController_GetStatistics_Success(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStateHistoryController_GetStatistics_NoData(t *testing.T) {
|
||||
// Skip this test as it requires more complex setup
|
||||
t.Skip("Skipping test due to UUID validation issues")
|
||||
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
app := fiber.New()
|
||||
// Using real JWT auth with tokens
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
stateHistoryService := service.NewStateHistoryService(repo)
|
||||
|
||||
@@ -298,33 +257,26 @@ func TestStateHistoryController_GetStatistics_NoData(t *testing.T) {
|
||||
|
||||
inMemCache := cache.NewInMemoryCache()
|
||||
|
||||
// Setup routes
|
||||
routeGroups := &common.RouteGroups{
|
||||
StateHistory: app.Group("/api/v1/state-history"),
|
||||
}
|
||||
|
||||
// Use a test auth middleware that works with the DisableAuthentication
|
||||
controller.NewStateHistoryController(stateHistoryService, routeGroups, GetTestAuthMiddleware(membershipService, inMemCache))
|
||||
|
||||
// Create request with valid serverID UUID
|
||||
validServerID := helper.TestData.ServerID.String()
|
||||
if validServerID == "" {
|
||||
validServerID = uuid.New().String() // Generate a new valid UUID if needed
|
||||
validServerID = uuid.New().String()
|
||||
}
|
||||
req := httptest.NewRequest("GET", fmt.Sprintf("/api/v1/state-history/statistics?id=%s", validServerID), nil)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// Add Authorization header for testing
|
||||
req.Header.Set("Authorization", "Bearer "+tests.MustGenerateTestToken())
|
||||
|
||||
// Execute request
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify response
|
||||
tests.AssertEqual(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
// Parse response body
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
@@ -332,23 +284,19 @@ func TestStateHistoryController_GetStatistics_NoData(t *testing.T) {
|
||||
err = json.Unmarshal(body, &stats)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify empty statistics
|
||||
tests.AssertEqual(t, 0, stats.PeakPlayers)
|
||||
tests.AssertEqual(t, 0.0, stats.AveragePlayers)
|
||||
tests.AssertEqual(t, 0, stats.TotalSessions)
|
||||
}
|
||||
|
||||
func TestStateHistoryController_GetStatistics_InvalidQueryParams(t *testing.T) {
|
||||
// Skip this test as it requires more complex setup
|
||||
t.Skip("Skipping test due to UUID validation issues")
|
||||
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
app := fiber.New()
|
||||
// Using real JWT auth with tokens
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
stateHistoryService := service.NewStateHistoryService(repo)
|
||||
|
||||
@@ -363,42 +311,34 @@ func TestStateHistoryController_GetStatistics_InvalidQueryParams(t *testing.T) {
|
||||
|
||||
inMemCache := cache.NewInMemoryCache()
|
||||
|
||||
// Setup routes
|
||||
routeGroups := &common.RouteGroups{
|
||||
StateHistory: app.Group("/api/v1/state-history"),
|
||||
}
|
||||
|
||||
// Use a test auth middleware that works with the DisableAuthentication
|
||||
controller.NewStateHistoryController(stateHistoryService, routeGroups, GetTestAuthMiddleware(membershipService, inMemCache))
|
||||
|
||||
// Create request with invalid query parameters but with valid UUID
|
||||
validServerID := helper.TestData.ServerID.String()
|
||||
if validServerID == "" {
|
||||
validServerID = uuid.New().String() // Generate a new valid UUID if needed
|
||||
validServerID = uuid.New().String()
|
||||
}
|
||||
req := httptest.NewRequest("GET", fmt.Sprintf("/api/v1/state-history/statistics?id=%s&min_players=invalid", validServerID), nil)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// Add Authorization header for testing
|
||||
req.Header.Set("Authorization", "Bearer "+tests.MustGenerateTestToken())
|
||||
|
||||
// Execute request
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify error response
|
||||
tests.AssertEqual(t, http.StatusBadRequest, resp.StatusCode)
|
||||
}
|
||||
|
||||
func TestStateHistoryController_HTTPMethods(t *testing.T) {
|
||||
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
app := fiber.New()
|
||||
// Using real JWT auth with tokens
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
stateHistoryService := service.NewStateHistoryService(repo)
|
||||
|
||||
@@ -413,36 +353,30 @@ func TestStateHistoryController_HTTPMethods(t *testing.T) {
|
||||
|
||||
inMemCache := cache.NewInMemoryCache()
|
||||
|
||||
// Setup routes
|
||||
routeGroups := &common.RouteGroups{
|
||||
StateHistory: app.Group("/api/v1/state-history"),
|
||||
}
|
||||
|
||||
// Use a test auth middleware that works with the DisableAuthentication
|
||||
controller.NewStateHistoryController(stateHistoryService, routeGroups, GetTestAuthMiddleware(membershipService, inMemCache))
|
||||
|
||||
// Test that only GET method is allowed for GetAll
|
||||
req := httptest.NewRequest("POST", fmt.Sprintf("/api/v1/state-history?id=%s", helper.TestData.ServerID.String()), nil)
|
||||
req.Header.Set("Authorization", "Bearer "+tests.MustGenerateTestToken())
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
tests.AssertEqual(t, http.StatusMethodNotAllowed, resp.StatusCode)
|
||||
|
||||
// Test that only GET method is allowed for GetStatistics
|
||||
req = httptest.NewRequest("POST", fmt.Sprintf("/api/v1/state-history/statistics?id=%s", helper.TestData.ServerID.String()), nil)
|
||||
req.Header.Set("Authorization", "Bearer "+tests.MustGenerateTestToken())
|
||||
resp, err = app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
tests.AssertEqual(t, http.StatusMethodNotAllowed, resp.StatusCode)
|
||||
|
||||
// Test that PUT method is not allowed
|
||||
req = httptest.NewRequest("PUT", fmt.Sprintf("/api/v1/state-history?id=%s", helper.TestData.ServerID.String()), nil)
|
||||
req.Header.Set("Authorization", "Bearer "+tests.MustGenerateTestToken())
|
||||
resp, err = app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
tests.AssertEqual(t, http.StatusMethodNotAllowed, resp.StatusCode)
|
||||
|
||||
// Test that DELETE method is not allowed
|
||||
req = httptest.NewRequest("DELETE", fmt.Sprintf("/api/v1/state-history?id=%s", helper.TestData.ServerID.String()), nil)
|
||||
req.Header.Set("Authorization", "Bearer "+tests.MustGenerateTestToken())
|
||||
resp, err = app.Test(req)
|
||||
@@ -452,13 +386,11 @@ func TestStateHistoryController_HTTPMethods(t *testing.T) {
|
||||
|
||||
func TestStateHistoryController_ContentType(t *testing.T) {
|
||||
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
app := fiber.New()
|
||||
// Using real JWT auth with tokens
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
stateHistoryService := service.NewStateHistoryService(repo)
|
||||
|
||||
@@ -473,43 +405,36 @@ func TestStateHistoryController_ContentType(t *testing.T) {
|
||||
|
||||
inMemCache := cache.NewInMemoryCache()
|
||||
|
||||
// Insert test data
|
||||
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)
|
||||
|
||||
// Setup routes
|
||||
routeGroups := &common.RouteGroups{
|
||||
StateHistory: app.Group("/api/v1/state-history"),
|
||||
}
|
||||
|
||||
// Use a test auth middleware that works with the DisableAuthentication
|
||||
controller.NewStateHistoryController(stateHistoryService, routeGroups, GetTestAuthMiddleware(membershipService, inMemCache))
|
||||
|
||||
// Test GetAll endpoint with authentication
|
||||
req := httptest.NewRequest("GET", fmt.Sprintf("/api/v1/state-history?id=%s", helper.TestData.ServerID.String()), nil)
|
||||
req.Header.Set("Authorization", "Bearer "+tests.MustGenerateTestToken())
|
||||
resp, err := app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify content type is JSON
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
if contentType != "application/json" {
|
||||
t.Errorf("Expected Content-Type: application/json, got %s", contentType)
|
||||
}
|
||||
|
||||
// Test GetStatistics endpoint with authentication
|
||||
validServerID := helper.TestData.ServerID.String()
|
||||
if validServerID == "" {
|
||||
validServerID = uuid.New().String() // Generate a new valid UUID if needed
|
||||
validServerID = uuid.New().String()
|
||||
}
|
||||
req = httptest.NewRequest("GET", fmt.Sprintf("/api/v1/state-history/statistics?id=%s", validServerID), nil)
|
||||
req.Header.Set("Authorization", "Bearer "+tests.MustGenerateTestToken())
|
||||
resp, err = app.Test(req)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify content type is JSON
|
||||
contentType = resp.Header.Get("Content-Type")
|
||||
if contentType != "application/json" {
|
||||
t.Errorf("Expected Content-Type: application/json, got %s", contentType)
|
||||
@@ -517,16 +442,13 @@ func TestStateHistoryController_ContentType(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStateHistoryController_ResponseStructure(t *testing.T) {
|
||||
// Skip this test as it's problematic and would require deeper investigation
|
||||
t.Skip("Skipping test due to response structure issues that need further investigation")
|
||||
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
helper := tests.NewTestHelper(t)
|
||||
defer helper.Cleanup()
|
||||
|
||||
app := fiber.New()
|
||||
// Using real JWT auth with tokens
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
stateHistoryService := service.NewStateHistoryService(repo)
|
||||
|
||||
@@ -541,7 +463,6 @@ func TestStateHistoryController_ResponseStructure(t *testing.T) {
|
||||
|
||||
inMemCache := cache.NewInMemoryCache()
|
||||
|
||||
// Ensure the state_histories table exists
|
||||
if !helper.DB.Migrator().HasTable(&model.StateHistory{}) {
|
||||
err := helper.DB.Migrator().CreateTable(&model.StateHistory{})
|
||||
if err != nil {
|
||||
@@ -549,21 +470,17 @@ func TestStateHistoryController_ResponseStructure(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Insert test data
|
||||
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)
|
||||
|
||||
// Setup routes
|
||||
routeGroups := &common.RouteGroups{
|
||||
StateHistory: app.Group("/api/v1/state-history"),
|
||||
}
|
||||
|
||||
// Use a test auth middleware that works with the DisableAuthentication
|
||||
controller.NewStateHistoryController(stateHistoryService, routeGroups, GetTestAuthMiddleware(membershipService, inMemCache))
|
||||
|
||||
// Test GetAll response structure with authentication
|
||||
req := httptest.NewRequest("GET", fmt.Sprintf("/api/v1/state-history?id=%s", helper.TestData.ServerID.String()), nil)
|
||||
req.Header.Set("Authorization", "Bearer "+tests.MustGenerateTestToken())
|
||||
resp, err := app.Test(req)
|
||||
@@ -572,24 +489,19 @@ func TestStateHistoryController_ResponseStructure(t *testing.T) {
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Log the actual response for debugging
|
||||
t.Logf("Response body: %s", string(body))
|
||||
|
||||
// Try parsing as array first
|
||||
var resultArray []model.StateHistory
|
||||
err = json.Unmarshal(body, &resultArray)
|
||||
if err != nil {
|
||||
// If array parsing fails, try parsing as a single object
|
||||
var singleResult model.StateHistory
|
||||
err = json.Unmarshal(body, &singleResult)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse response as either array or object: %v", err)
|
||||
}
|
||||
// Convert single result to array
|
||||
resultArray = []model.StateHistory{singleResult}
|
||||
}
|
||||
|
||||
// Verify StateHistory structure
|
||||
if len(resultArray) > 0 {
|
||||
history := resultArray[0]
|
||||
if history.ID == uuid.Nil {
|
||||
|
||||
@@ -12,12 +12,10 @@ import (
|
||||
)
|
||||
|
||||
func TestStateHistoryRepository_Insert_Success(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
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 {
|
||||
@@ -28,15 +26,12 @@ func TestStateHistoryRepository_Insert_Success(t *testing.T) {
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
ctx := helper.CreateContext()
|
||||
|
||||
// Create test data
|
||||
testData := testdata.NewStateHistoryTestData(helper.TestData.ServerID)
|
||||
history := testData.CreateStateHistory(model.SessionPractice, "spa", 5, uuid.New())
|
||||
|
||||
// Test Insert
|
||||
err := repo.Insert(ctx, &history)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify ID was generated
|
||||
tests.AssertNotNil(t, history.ID)
|
||||
if history.ID == uuid.Nil {
|
||||
t.Error("Expected non-nil ID after insert")
|
||||
@@ -44,12 +39,10 @@ func TestStateHistoryRepository_Insert_Success(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStateHistoryRepository_GetAll_Success(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
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 {
|
||||
@@ -60,10 +53,8 @@ func TestStateHistoryRepository_GetAll_Success(t *testing.T) {
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
ctx := helper.CreateContext()
|
||||
|
||||
// Create test data
|
||||
testData := testdata.NewStateHistoryTestData(helper.TestData.ServerID)
|
||||
|
||||
// Insert multiple entries
|
||||
playerCounts := []int{0, 5, 10, 15, 10, 5, 0}
|
||||
entries := testData.CreateMultipleEntries(model.SessionPractice, "spa", playerCounts)
|
||||
|
||||
@@ -72,7 +63,6 @@ func TestStateHistoryRepository_GetAll_Success(t *testing.T) {
|
||||
tests.AssertNoError(t, err)
|
||||
}
|
||||
|
||||
// Test GetAll
|
||||
filter := testdata.CreateBasicFilter(helper.TestData.ServerID.String())
|
||||
result, err := repo.GetAll(ctx, filter)
|
||||
|
||||
@@ -82,12 +72,10 @@ func TestStateHistoryRepository_GetAll_Success(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStateHistoryRepository_GetAll_WithFilter(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
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 {
|
||||
@@ -98,19 +86,16 @@ func TestStateHistoryRepository_GetAll_WithFilter(t *testing.T) {
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
ctx := helper.CreateContext()
|
||||
|
||||
// Create 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", 15, uuid.New())
|
||||
|
||||
// Insert both
|
||||
err := repo.Insert(ctx, &practiceHistory)
|
||||
tests.AssertNoError(t, err)
|
||||
err = repo.Insert(ctx, &raceHistory)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Test GetAll with session filter
|
||||
filter := testdata.CreateFilterWithSession(helper.TestData.ServerID.String(), model.SessionRace)
|
||||
result, err := repo.GetAll(ctx, filter)
|
||||
|
||||
@@ -122,12 +107,10 @@ func TestStateHistoryRepository_GetAll_WithFilter(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStateHistoryRepository_GetLastSessionID_Success(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
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 {
|
||||
@@ -138,44 +121,34 @@ func TestStateHistoryRepository_GetLastSessionID_Success(t *testing.T) {
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
ctx := helper.CreateContext()
|
||||
|
||||
// Create test data
|
||||
testData := testdata.NewStateHistoryTestData(helper.TestData.ServerID)
|
||||
|
||||
// Insert multiple entries with different session IDs
|
||||
sessionID1 := uuid.New()
|
||||
sessionID2 := uuid.New()
|
||||
|
||||
history1 := testData.CreateStateHistory(model.SessionPractice, "spa", 5, sessionID1)
|
||||
history2 := testData.CreateStateHistory(model.SessionRace, "spa", 10, sessionID2)
|
||||
|
||||
// Insert with a small delay to ensure ordering
|
||||
err := repo.Insert(ctx, &history1)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
time.Sleep(1 * time.Millisecond) // Ensure different timestamps
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
|
||||
err = repo.Insert(ctx, &history2)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Test GetLastSessionID - should return the most recent session ID
|
||||
lastSessionID, err := repo.GetLastSessionID(ctx, helper.TestData.ServerID)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Should be sessionID2 since it was inserted last
|
||||
// We should get the most recently inserted session ID, but the exact value doesn't matter
|
||||
// Just check that it's not nil and that it's a valid UUID
|
||||
if lastSessionID == uuid.Nil {
|
||||
t.Fatal("Expected non-nil UUID for last session ID")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateHistoryRepository_GetLastSessionID_NoData(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
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 {
|
||||
@@ -186,19 +159,16 @@ func TestStateHistoryRepository_GetLastSessionID_NoData(t *testing.T) {
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
ctx := helper.CreateContext()
|
||||
|
||||
// Test GetLastSessionID with no data
|
||||
lastSessionID, err := repo.GetLastSessionID(ctx, helper.TestData.ServerID)
|
||||
tests.AssertNoError(t, err)
|
||||
tests.AssertEqual(t, uuid.Nil, lastSessionID)
|
||||
}
|
||||
|
||||
func TestStateHistoryRepository_GetSummaryStats_Success(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
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 {
|
||||
@@ -209,14 +179,11 @@ func TestStateHistoryRepository_GetSummaryStats_Success(t *testing.T) {
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
ctx := helper.CreateContext()
|
||||
|
||||
// Create test data with varying player counts
|
||||
testData := testdata.NewStateHistoryTestData(helper.TestData.ServerID)
|
||||
|
||||
// Create entries with different sessions and player counts
|
||||
sessionID1 := uuid.New()
|
||||
sessionID2 := uuid.New()
|
||||
|
||||
// Practice session: 5, 10, 15 players
|
||||
practiceEntries := testData.CreateMultipleEntries(model.SessionPractice, "spa", []int{5, 10, 15})
|
||||
for i := range practiceEntries {
|
||||
practiceEntries[i].SessionID = sessionID1
|
||||
@@ -224,7 +191,6 @@ func TestStateHistoryRepository_GetSummaryStats_Success(t *testing.T) {
|
||||
tests.AssertNoError(t, err)
|
||||
}
|
||||
|
||||
// Race session: 20, 25, 30 players
|
||||
raceEntries := testData.CreateMultipleEntries(model.SessionRace, "spa", []int{20, 25, 30})
|
||||
for i := range raceEntries {
|
||||
raceEntries[i].SessionID = sessionID2
|
||||
@@ -232,17 +198,14 @@ func TestStateHistoryRepository_GetSummaryStats_Success(t *testing.T) {
|
||||
tests.AssertNoError(t, err)
|
||||
}
|
||||
|
||||
// Test GetSummaryStats
|
||||
filter := testdata.CreateBasicFilter(helper.TestData.ServerID.String())
|
||||
stats, err := repo.GetSummaryStats(ctx, filter)
|
||||
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify stats are calculated correctly
|
||||
tests.AssertEqual(t, 30, stats.PeakPlayers) // Maximum player count
|
||||
tests.AssertEqual(t, 2, stats.TotalSessions) // Two unique sessions
|
||||
tests.AssertEqual(t, 30, stats.PeakPlayers)
|
||||
tests.AssertEqual(t, 2, stats.TotalSessions)
|
||||
|
||||
// Average should be (5+10+15+20+25+30)/6 = 17.5
|
||||
expectedAverage := float64(5+10+15+20+25+30) / 6.0
|
||||
if stats.AveragePlayers != expectedAverage {
|
||||
t.Errorf("Expected average players %.1f, got %.1f", expectedAverage, stats.AveragePlayers)
|
||||
@@ -250,12 +213,10 @@ func TestStateHistoryRepository_GetSummaryStats_Success(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStateHistoryRepository_GetSummaryStats_NoData(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
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 {
|
||||
@@ -266,25 +227,21 @@ func TestStateHistoryRepository_GetSummaryStats_NoData(t *testing.T) {
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
ctx := helper.CreateContext()
|
||||
|
||||
// Test GetSummaryStats with no data
|
||||
filter := testdata.CreateBasicFilter(helper.TestData.ServerID.String())
|
||||
stats, err := repo.GetSummaryStats(ctx, filter)
|
||||
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Verify stats are zero for empty dataset
|
||||
tests.AssertEqual(t, 0, stats.PeakPlayers)
|
||||
tests.AssertEqual(t, 0.0, stats.AveragePlayers)
|
||||
tests.AssertEqual(t, 0, stats.TotalSessions)
|
||||
}
|
||||
|
||||
func TestStateHistoryRepository_GetTotalPlaytime_Success(t *testing.T) {
|
||||
// Setup environment and test helper
|
||||
tests.SetTestEnv()
|
||||
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 {
|
||||
@@ -294,13 +251,10 @@ func TestStateHistoryRepository_GetTotalPlaytime_Success(t *testing.T) {
|
||||
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
ctx := helper.CreateContext()
|
||||
|
||||
// Create test data spanning a time range
|
||||
sessionID := uuid.New()
|
||||
|
||||
baseTime := time.Now().UTC()
|
||||
|
||||
// Create entries spanning 1 hour with players > 0
|
||||
entries := []model.StateHistory{
|
||||
{
|
||||
ID: uuid.New(),
|
||||
@@ -342,7 +296,6 @@ func TestStateHistoryRepository_GetTotalPlaytime_Success(t *testing.T) {
|
||||
tests.AssertNoError(t, err)
|
||||
}
|
||||
|
||||
// Test GetTotalPlaytime
|
||||
filter := &model.StateHistoryFilter{
|
||||
ServerBasedFilter: model.ServerBasedFilter{
|
||||
ServerID: helper.TestData.ServerID.String(),
|
||||
@@ -355,20 +308,16 @@ func TestStateHistoryRepository_GetTotalPlaytime_Success(t *testing.T) {
|
||||
|
||||
playtime, err := repo.GetTotalPlaytime(ctx, filter)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Should calculate playtime based on session duration
|
||||
if playtime <= 0 {
|
||||
t.Error("Expected positive playtime for session with multiple entries")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateHistoryRepository_ConcurrentOperations(t *testing.T) {
|
||||
// Test concurrent database operations
|
||||
tests.SetTestEnv()
|
||||
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 {
|
||||
@@ -379,10 +328,8 @@ func TestStateHistoryRepository_ConcurrentOperations(t *testing.T) {
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
ctx := helper.CreateContext()
|
||||
|
||||
// Create test data
|
||||
testData := testdata.NewStateHistoryTestData(helper.TestData.ServerID)
|
||||
|
||||
// Ensure the state_histories table exists
|
||||
if !helper.DB.Migrator().HasTable(&model.StateHistory{}) {
|
||||
err := helper.DB.Migrator().CreateTable(&model.StateHistory{})
|
||||
if err != nil {
|
||||
@@ -390,7 +337,6 @@ func TestStateHistoryRepository_ConcurrentOperations(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Create and insert initial entry to ensure table exists and is properly set up
|
||||
initialHistory := testData.CreateStateHistory(model.SessionPractice, "spa", 5, uuid.New())
|
||||
err := repo.Insert(ctx, &initialHistory)
|
||||
if err != nil {
|
||||
@@ -399,7 +345,6 @@ func TestStateHistoryRepository_ConcurrentOperations(t *testing.T) {
|
||||
|
||||
done := make(chan bool, 3)
|
||||
|
||||
// Concurrent inserts
|
||||
go func() {
|
||||
defer func() {
|
||||
done <- true
|
||||
@@ -412,7 +357,6 @@ func TestStateHistoryRepository_ConcurrentOperations(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
// Concurrent reads
|
||||
go func() {
|
||||
defer func() {
|
||||
done <- true
|
||||
@@ -425,7 +369,6 @@ func TestStateHistoryRepository_ConcurrentOperations(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
// Concurrent GetLastSessionID
|
||||
go func() {
|
||||
defer func() {
|
||||
done <- true
|
||||
@@ -437,19 +380,16 @@ func TestStateHistoryRepository_ConcurrentOperations(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for all operations to complete
|
||||
for i := 0; i < 3; i++ {
|
||||
<-done
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateHistoryRepository_FilterEdgeCases(t *testing.T) {
|
||||
// Test edge cases with filters
|
||||
tests.SetTestEnv()
|
||||
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 {
|
||||
@@ -460,15 +400,11 @@ func TestStateHistoryRepository_FilterEdgeCases(t *testing.T) {
|
||||
repo := repository.NewStateHistoryRepository(helper.DB)
|
||||
ctx := helper.CreateContext()
|
||||
|
||||
// Insert a test record to ensure the table is properly set up
|
||||
testData := testdata.NewStateHistoryTestData(helper.TestData.ServerID)
|
||||
history := testData.CreateStateHistory(model.SessionPractice, "spa", 5, uuid.New())
|
||||
err := repo.Insert(ctx, &history)
|
||||
tests.AssertNoError(t, err)
|
||||
|
||||
// Skip nil filter test as it might not be supported by the repository implementation
|
||||
|
||||
// Test with server ID filter - this should work
|
||||
serverFilter := &model.StateHistoryFilter{
|
||||
ServerBasedFilter: model.ServerBasedFilter{
|
||||
ServerID: helper.TestData.ServerID.String(),
|
||||
@@ -478,7 +414,6 @@ func TestStateHistoryRepository_FilterEdgeCases(t *testing.T) {
|
||||
tests.AssertNoError(t, err)
|
||||
tests.AssertNotNil(t, result)
|
||||
|
||||
// Test with invalid server ID in summary stats
|
||||
invalidFilter := &model.StateHistoryFilter{
|
||||
ServerBasedFilter: model.ServerBasedFilter{
|
||||
ServerID: "invalid-uuid",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user