package ground_spawn import ( "testing" ) // Mock implementations are in test_utils.go // Benchmark GroundSpawn operations func BenchmarkGroundSpawn(b *testing.B) { config := GroundSpawnConfig{ GroundSpawnID: 1, CollectionSkill: SkillGathering, NumberHarvests: 10, AttemptsPerHarvest: 2, RandomizeHeading: true, Location: SpawnLocation{ X: 100.0, Y: 200.0, Z: 300.0, Heading: 45.0, GridID: 1, }, Name: "Benchmark Node", Description: "A benchmark harvestable node", } gs := NewGroundSpawn(config) b.Run("GetNumberHarvests", func(b *testing.B) { for b.Loop() { _ = gs.GetNumberHarvests() } }) b.Run("SetNumberHarvests", func(b *testing.B) { b.ResetTimer() for i := 0; b.Loop(); i++ { gs.SetNumberHarvests(int8(i % 10)) } }) b.Run("GetCollectionSkill", func(b *testing.B) { b.ResetTimer() for b.Loop() { _ = gs.GetCollectionSkill() } }) b.Run("SetCollectionSkill", func(b *testing.B) { skills := []string{SkillGathering, SkillMining, SkillFishing, SkillTrapping} b.ResetTimer() for i := 0; b.Loop(); i++ { gs.SetCollectionSkill(skills[i%len(skills)]) } }) b.Run("IsAvailable", func(b *testing.B) { b.ResetTimer() for b.Loop() { _ = gs.IsAvailable() } }) b.Run("IsDepleted", func(b *testing.B) { b.ResetTimer() for b.Loop() { _ = gs.IsDepleted() } }) b.Run("GetHarvestMessageName", func(b *testing.B) { b.ResetTimer() for i := 0; b.Loop(); i++ { _ = gs.GetHarvestMessageName(i%2 == 0, i%4 == 0) } }) b.Run("GetHarvestSpellType", func(b *testing.B) { b.ResetTimer() for b.Loop() { _ = gs.GetHarvestSpellType() } }) b.Run("Copy", func(b *testing.B) { b.ResetTimer() for b.Loop() { copy := gs.Copy() _ = copy } }) b.Run("Respawn", func(b *testing.B) { b.ResetTimer() for b.Loop() { gs.Respawn() } }) } // Benchmark Manager operations func BenchmarkManager(b *testing.B) { manager := NewManager(nil, &mockLogger{}) // Pre-populate with ground spawns for i := int32(1); i <= 100; i++ { config := GroundSpawnConfig{ GroundSpawnID: i, CollectionSkill: SkillGathering, NumberHarvests: 5, AttemptsPerHarvest: 1, Location: SpawnLocation{ X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30), Heading: float32(i * 45), GridID: 1, }, Name: "Benchmark Node", Description: "Benchmark node", } gs := manager.CreateGroundSpawn(config) _ = gs } b.Run("GetGroundSpawn", func(b *testing.B) { b.ResetTimer() for i := 0; b.Loop(); i++ { spawnID := int32((i % 100) + 1) _ = manager.GetGroundSpawn(spawnID) } }) b.Run("CreateGroundSpawn", func(b *testing.B) { b.ResetTimer() for i := 0; b.Loop(); i++ { config := GroundSpawnConfig{ GroundSpawnID: int32(2000 + i), CollectionSkill: SkillMining, NumberHarvests: 3, AttemptsPerHarvest: 1, Location: SpawnLocation{ X: float32(i), Y: float32(i * 2), Z: float32(i * 3), Heading: 0, GridID: 1, }, Name: "New Node", Description: "New benchmark node", } _ = manager.CreateGroundSpawn(config) } }) b.Run("GetGroundSpawnsByZone", func(b *testing.B) { b.ResetTimer() for b.Loop() { _ = manager.GetGroundSpawnsByZone(1) } }) b.Run("GetGroundSpawnCount", func(b *testing.B) { b.ResetTimer() for b.Loop() { _ = manager.GetGroundSpawnCount() } }) b.Run("GetActiveGroundSpawns", func(b *testing.B) { b.ResetTimer() for b.Loop() { _ = manager.GetActiveGroundSpawns() } }) b.Run("GetDepletedGroundSpawns", func(b *testing.B) { b.ResetTimer() for b.Loop() { _ = manager.GetDepletedGroundSpawns() } }) b.Run("GetStatistics", func(b *testing.B) { b.ResetTimer() for b.Loop() { _ = manager.GetStatistics() } }) b.Run("ResetStatistics", func(b *testing.B) { b.ResetTimer() for b.Loop() { manager.ResetStatistics() } }) b.Run("ProcessRespawns", func(b *testing.B) { b.ResetTimer() for b.Loop() { manager.ProcessRespawns() } }) } // Benchmark concurrent operations func BenchmarkConcurrentOperations(b *testing.B) { b.Run("GroundSpawnConcurrentReads", func(b *testing.B) { config := GroundSpawnConfig{ GroundSpawnID: 1, CollectionSkill: SkillGathering, NumberHarvests: 10, AttemptsPerHarvest: 1, Location: SpawnLocation{ X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1, }, Name: "Concurrent Node", Description: "Concurrent benchmark node", } gs := NewGroundSpawn(config) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { switch i % 4 { case 0: _ = gs.GetNumberHarvests() case 1: _ = gs.GetCollectionSkill() case 2: _ = gs.IsAvailable() case 3: _ = gs.GetHarvestSpellType() } i++ } }) }) b.Run("GroundSpawnConcurrentWrites", func(b *testing.B) { config := GroundSpawnConfig{ GroundSpawnID: 1, CollectionSkill: SkillGathering, NumberHarvests: 10, AttemptsPerHarvest: 1, Location: SpawnLocation{ X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1, }, Name: "Concurrent Node", Description: "Concurrent benchmark node", } gs := NewGroundSpawn(config) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { switch i % 3 { case 0: gs.SetNumberHarvests(int8(i % 10)) case 1: gs.SetCollectionSkill(SkillMining) case 2: gs.SetRandomizeHeading(i%2 == 0) } i++ } }) }) b.Run("ManagerConcurrentOperations", func(b *testing.B) { manager := NewManager(nil, &mockLogger{}) // Pre-populate for i := int32(1); i <= 10; i++ { config := GroundSpawnConfig{ GroundSpawnID: i, CollectionSkill: SkillGathering, NumberHarvests: 5, AttemptsPerHarvest: 1, Location: SpawnLocation{ X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30), Heading: 0, GridID: 1, }, Name: "Manager Node", Description: "Manager benchmark node", } manager.CreateGroundSpawn(config) } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { spawnID := int32((i % 10) + 1) switch i % 5 { case 0: _ = manager.GetGroundSpawn(spawnID) case 1: _ = manager.GetGroundSpawnsByZone(1) case 2: _ = manager.GetStatistics() case 3: _ = manager.GetActiveGroundSpawns() case 4: manager.ProcessRespawns() } i++ } }) }) } // Memory allocation benchmarks func BenchmarkMemoryAllocations(b *testing.B) { b.Run("GroundSpawnCreation", func(b *testing.B) { config := GroundSpawnConfig{ GroundSpawnID: 1, CollectionSkill: SkillGathering, NumberHarvests: 5, AttemptsPerHarvest: 1, Location: SpawnLocation{ X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1, }, Name: "Memory Test Node", Description: "Memory test node", } b.ReportAllocs() b.ResetTimer() for b.Loop() { _ = NewGroundSpawn(config) } }) b.Run("ManagerCreation", func(b *testing.B) { b.ReportAllocs() b.ResetTimer() for b.Loop() { _ = NewManager(nil, &mockLogger{}) } }) b.Run("GroundSpawnCopy", func(b *testing.B) { config := GroundSpawnConfig{ GroundSpawnID: 1, CollectionSkill: SkillGathering, NumberHarvests: 5, AttemptsPerHarvest: 1, Location: SpawnLocation{ X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1, }, Name: "Copy Test Node", Description: "Copy test node", } gs := NewGroundSpawn(config) b.ReportAllocs() b.ResetTimer() for b.Loop() { _ = gs.Copy() } }) b.Run("StatisticsGeneration", func(b *testing.B) { manager := NewManager(nil, &mockLogger{}) // Add some data for meaningful statistics for i := int32(1); i <= 10; i++ { config := GroundSpawnConfig{ GroundSpawnID: i, CollectionSkill: SkillGathering, NumberHarvests: 5, AttemptsPerHarvest: 1, Location: SpawnLocation{ X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30), Heading: 0, GridID: 1, }, Name: "Stats Node", Description: "Stats test node", } manager.CreateGroundSpawn(config) } // Add some harvest statistics manager.mutex.Lock() manager.totalHarvests = 1000 manager.successfulHarvests = 850 manager.rareItemsHarvested = 50 manager.skillUpsGenerated = 200 manager.harvestsBySkill[SkillGathering] = 600 manager.harvestsBySkill[SkillMining] = 400 manager.mutex.Unlock() b.ReportAllocs() b.ResetTimer() for b.Loop() { _ = manager.GetStatistics() } }) } // Contention benchmarks func BenchmarkContention(b *testing.B) { b.Run("HighContentionReads", func(b *testing.B) { config := GroundSpawnConfig{ GroundSpawnID: 1, CollectionSkill: SkillGathering, NumberHarvests: 10, AttemptsPerHarvest: 1, Location: SpawnLocation{ X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1, }, Name: "Contention Node", Description: "Contention test node", } gs := NewGroundSpawn(config) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = gs.GetNumberHarvests() } }) }) b.Run("HighContentionWrites", func(b *testing.B) { config := GroundSpawnConfig{ GroundSpawnID: 1, CollectionSkill: SkillGathering, NumberHarvests: 10, AttemptsPerHarvest: 1, Location: SpawnLocation{ X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1, }, Name: "Contention Node", Description: "Contention test node", } gs := NewGroundSpawn(config) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { gs.SetNumberHarvests(int8(i % 10)) i++ } }) }) b.Run("MixedReadWrite", func(b *testing.B) { config := GroundSpawnConfig{ GroundSpawnID: 1, CollectionSkill: SkillGathering, NumberHarvests: 10, AttemptsPerHarvest: 1, Location: SpawnLocation{ X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1, }, Name: "Mixed Node", Description: "Mixed operations test node", } gs := NewGroundSpawn(config) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { if i%10 == 0 { // 10% writes gs.SetNumberHarvests(int8(i % 5)) } else { // 90% reads _ = gs.GetNumberHarvests() } i++ } }) }) b.Run("ManagerHighContention", func(b *testing.B) { manager := NewManager(nil, &mockLogger{}) // Pre-populate for i := int32(1); i <= 5; i++ { config := GroundSpawnConfig{ GroundSpawnID: i, CollectionSkill: SkillGathering, NumberHarvests: 5, AttemptsPerHarvest: 1, Location: SpawnLocation{ X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30), Heading: 0, GridID: 1, }, Name: "Contention Node", Description: "Manager contention test", } manager.CreateGroundSpawn(config) } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = manager.GetGroundSpawn(1) } }) }) } // Scalability benchmarks func BenchmarkScalability(b *testing.B) { sizes := []int{10, 100, 1000} for _, size := range sizes { b.Run("GroundSpawnLookup_"+string(rune(size)), func(b *testing.B) { manager := NewManager(nil, &mockLogger{}) // Pre-populate with varying sizes for i := int32(1); i <= int32(size); i++ { config := GroundSpawnConfig{ GroundSpawnID: i, CollectionSkill: SkillGathering, NumberHarvests: 5, AttemptsPerHarvest: 1, Location: SpawnLocation{ X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30), Heading: 0, GridID: 1, }, Name: "Scale Node", Description: "Scalability test node", } manager.CreateGroundSpawn(config) } b.ResetTimer() for i := 0; b.Loop(); i++ { spawnID := int32((i % size) + 1) _ = manager.GetGroundSpawn(spawnID) } }) } for _, size := range sizes { b.Run("ZoneLookup_"+string(rune(size)), func(b *testing.B) { manager := NewManager(nil, &mockLogger{}) // Pre-populate with varying sizes for i := int32(1); i <= int32(size); i++ { config := GroundSpawnConfig{ GroundSpawnID: i, CollectionSkill: SkillGathering, NumberHarvests: 5, AttemptsPerHarvest: 1, Location: SpawnLocation{ X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30), Heading: 0, GridID: 1, }, Name: "Zone Node", Description: "Zone scalability test", } manager.CreateGroundSpawn(config) } b.ResetTimer() for b.Loop() { _ = manager.GetGroundSpawnsByZone(1) } }) } }