package channelserver import ( "net" "sync" "testing" ) func createTestChannels(count int) []*Server { channels := make([]*Server, count) for i := 0; i < count; i++ { s := createTestServer() s.ID = uint16(0x1010 + i) s.IP = "10.0.0.1" s.Port = uint16(54001 + i) s.GlobalID = "0101" s.userBinary = NewUserBinaryStore() channels[i] = s } return channels } func TestLocalRegistryFindSessionByCharID(t *testing.T) { channels := createTestChannels(2) reg := NewLocalChannelRegistry(channels) conn1 := &mockConn{} sess1 := createTestSessionForServer(channels[0], conn1, 100, "Alice") channels[0].Lock() channels[0].sessions[conn1] = sess1 channels[0].Unlock() conn2 := &mockConn{} sess2 := createTestSessionForServer(channels[1], conn2, 200, "Bob") channels[1].Lock() channels[1].sessions[conn2] = sess2 channels[1].Unlock() // Find on first channel found := reg.FindSessionByCharID(100) if found == nil || found.charID != 100 { t.Errorf("FindSessionByCharID(100) = %v, want session with charID 100", found) } // Find on second channel found = reg.FindSessionByCharID(200) if found == nil || found.charID != 200 { t.Errorf("FindSessionByCharID(200) = %v, want session with charID 200", found) } // Not found found = reg.FindSessionByCharID(999) if found != nil { t.Errorf("FindSessionByCharID(999) = %v, want nil", found) } } func TestLocalRegistryFindChannelForStage(t *testing.T) { channels := createTestChannels(2) channels[0].GlobalID = "0101" channels[1].GlobalID = "0102" reg := NewLocalChannelRegistry(channels) channels[1].stages.Store("sl2Qs123p0a0u42", NewStage("sl2Qs123p0a0u42")) gid := reg.FindChannelForStage("u42") if gid != "0102" { t.Errorf("FindChannelForStage(u42) = %q, want %q", gid, "0102") } gid = reg.FindChannelForStage("u999") if gid != "" { t.Errorf("FindChannelForStage(u999) = %q, want empty", gid) } } func TestLocalRegistryDisconnectUser(t *testing.T) { channels := createTestChannels(1) reg := NewLocalChannelRegistry(channels) conn := &mockConn{} sess := createTestSessionForServer(channels[0], conn, 42, "Target") channels[0].Lock() channels[0].sessions[conn] = sess channels[0].Unlock() reg.DisconnectUser([]uint32{42}) if !conn.WasClosed() { t.Error("DisconnectUser should have closed the connection for charID 42") } } func TestLocalRegistrySearchSessions(t *testing.T) { channels := createTestChannels(2) reg := NewLocalChannelRegistry(channels) // Add 3 sessions across 2 channels for i, ch := range channels { conn := &mockConn{} sess := createTestSessionForServer(ch, conn, uint32(i+1), "Player") sess.stage = NewStage("sl1Ns200p0a0u0") ch.Lock() ch.sessions[conn] = sess ch.Unlock() } conn3 := &mockConn{} sess3 := createTestSessionForServer(channels[0], conn3, 3, "Player") sess3.stage = NewStage("sl1Ns200p0a0u0") channels[0].Lock() channels[0].sessions[conn3] = sess3 channels[0].Unlock() // Search all results := reg.SearchSessions(func(s SessionSnapshot) bool { return true }, 10) if len(results) != 3 { t.Errorf("SearchSessions(all) returned %d results, want 3", len(results)) } // Search with max results = reg.SearchSessions(func(s SessionSnapshot) bool { return true }, 2) if len(results) != 2 { t.Errorf("SearchSessions(max=2) returned %d results, want 2", len(results)) } // Search with predicate results = reg.SearchSessions(func(s SessionSnapshot) bool { return s.CharID == 1 }, 10) if len(results) != 1 { t.Errorf("SearchSessions(charID==1) returned %d results, want 1", len(results)) } } func TestLocalRegistrySearchStages(t *testing.T) { channels := createTestChannels(1) reg := NewLocalChannelRegistry(channels) channels[0].stages.Store("sl2Ls210test1", NewStage("sl2Ls210test1")) channels[0].stages.Store("sl2Ls210test2", NewStage("sl2Ls210test2")) channels[0].stages.Store("sl1Ns200other", NewStage("sl1Ns200other")) results := reg.SearchStages("sl2Ls210", 10) if len(results) != 2 { t.Errorf("SearchStages(sl2Ls210) returned %d results, want 2", len(results)) } results = reg.SearchStages("sl2Ls210", 1) if len(results) != 1 { t.Errorf("SearchStages(sl2Ls210, max=1) returned %d results, want 1", len(results)) } } func TestLocalRegistryConcurrentAccess(t *testing.T) { channels := createTestChannels(2) reg := NewLocalChannelRegistry(channels) // Populate some sessions for _, ch := range channels { for i := 0; i < 10; i++ { conn := &mockConn{remoteAddr: &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 50000 + i}} sess := createTestSessionForServer(ch, conn, uint32(i+1), "Player") sess.stage = NewStage("sl1Ns200p0a0u0") ch.Lock() ch.sessions[conn] = sess ch.Unlock() } } // Run concurrent operations var wg sync.WaitGroup for i := 0; i < 50; i++ { wg.Add(3) go func(id int) { defer wg.Done() _ = reg.FindSessionByCharID(uint32(id%10 + 1)) }(i) go func() { defer wg.Done() _ = reg.FindChannelForStage("u0") }() go func() { defer wg.Done() _ = reg.SearchSessions(func(s SessionSnapshot) bool { return true }, 5) }() } wg.Wait() }