package voice import ( "sync" "testing" ) func TestPublishPacket(t *testing.T) { router := NewRouter() packet := NewPacket("user-1", "channel-1", 1, 1000, 5000, []byte("audio data"), 12345) err := router.PublishPacket(packet) if err != nil { t.Errorf("PublishPacket() error = %v", err) } // Test with nil packet err = router.PublishPacket(nil) if err == nil { t.Error("PublishPacket() should error on nil packet") } } func TestSubscribe(t *testing.T) { router := NewRouter() channelID := "channel-1" receivedPackets := make([]*Packet, 0) var mu sync.Mutex subscriber := func(p *Packet) error { mu.Lock() receivedPackets = append(receivedPackets, p) mu.Unlock() return nil } router.Subscribe(channelID, subscriber) // Publish packet packet := NewPacket("user-1", "channel-1", 1, 1000, 5000, []byte("audio"), 12345) router.PublishPacket(packet) // Give some time for async processing if len(receivedPackets) != 1 { t.Errorf("Expected 1 received packet, got %d", len(receivedPackets)) } } func TestMultipleSubscribers(t *testing.T) { router := NewRouter() channelID := "channel-1" received1 := make([]*Packet, 0) received2 := make([]*Packet, 0) var mu1, mu2 sync.Mutex subscriber1 := func(p *Packet) error { mu1.Lock() received1 = append(received1, p) mu1.Unlock() return nil } subscriber2 := func(p *Packet) error { mu2.Lock() received2 = append(received2, p) mu2.Unlock() return nil } router.Subscribe(channelID, subscriber1) router.Subscribe(channelID, subscriber2) packet := NewPacket("user-1", "channel-1", 1, 1000, 5000, []byte("audio"), 12345) router.PublishPacket(packet) if len(received1) != 1 { t.Errorf("Subscriber1 expected 1 packet, got %d", len(received1)) } if len(received2) != 1 { t.Errorf("Subscriber2 expected 1 packet, got %d", len(received2)) } } func TestUnsubscribe(t *testing.T) { router := NewRouter() channelID := "channel-1" subscriber := func(p *Packet) error { return nil } router.Subscribe(channelID, subscriber) count := router.GetSubscriberCount(channelID) if count != 1 { t.Errorf("Expected 1 subscriber, got %d", count) } // Note: Unsubscribe is a placeholder in this implementation // In production, we'd track subscribers by ID for proper cleanup router.Unsubscribe(channelID, subscriber) } func TestGetSubscriberCount(t *testing.T) { router := NewRouter() channelID := "channel-1" subscriber := func(p *Packet) error { return nil } // Initially no subscribers count := router.GetSubscriberCount(channelID) if count != 0 { t.Errorf("Expected 0 subscribers, got %d", count) } // Add subscriber router.Subscribe(channelID, subscriber) count = router.GetSubscriberCount(channelID) if count != 1 { t.Errorf("Expected 1 subscriber, got %d", count) } // Add another subscriber router.Subscribe(channelID, subscriber) count = router.GetSubscriberCount(channelID) if count != 2 { t.Errorf("Expected 2 subscribers, got %d", count) } // Note: Unsubscribe is a placeholder - doesn't actually remove in current implementation router.Unsubscribe(channelID, subscriber) } func TestNilSubscriber(t *testing.T) { router := NewRouter() channelID := "channel-1" // Subscribe with nil should not error router.Subscribe(channelID, nil) // Should handle gracefully packet := NewPacket("user-1", "channel-1", 1, 1000, 5000, []byte("audio"), 12345) err := router.PublishPacket(packet) if err != nil { t.Errorf("PublishPacket() with nil subscriber error = %v", err) } } func TestMultipleChannels(t *testing.T) { router := NewRouter() received1 := make([]*Packet, 0) received2 := make([]*Packet, 0) var mu1, mu2 sync.Mutex subscriber1 := func(p *Packet) error { mu1.Lock() received1 = append(received1, p) mu1.Unlock() return nil } subscriber2 := func(p *Packet) error { mu2.Lock() received2 = append(received2, p) mu2.Unlock() return nil } // Subscribe to different channels router.Subscribe("channel-1", subscriber1) router.Subscribe("channel-2", subscriber2) // Publish to channel-1 packet1 := NewPacket("user-1", "channel-1", 1, 1000, 5000, []byte("audio"), 12345) router.PublishPacket(packet1) // Publish to channel-2 packet2 := NewPacket("user-2", "channel-2", 1, 1000, 5000, []byte("audio"), 12345) router.PublishPacket(packet2) if len(received1) != 1 { t.Errorf("Channel-1 subscriber expected 1 packet, got %d", len(received1)) } if len(received2) != 1 { t.Errorf("Channel-2 subscriber expected 1 packet, got %d", len(received2)) } } func TestPacketSize(t *testing.T) { tests := []struct { name string payload []byte wantSize int }{ { name: "empty payload", payload: []byte{}, wantSize: 0, }, { name: "small payload", payload: []byte("audio"), wantSize: 5, }, { name: "large payload", payload: make([]byte, 1024), wantSize: 1024, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { packet := NewPacket("user-1", "channel-1", 1, 1000, 5000, tt.payload, 12345) if packet.Size() != tt.wantSize { t.Errorf("Packet.Size() = %d, want %d", packet.Size(), tt.wantSize) } }) } } func TestPacketFields(t *testing.T) { payload := []byte("test audio") packet := NewPacket("user-1", "channel-1", 42, 1000, 5000, payload, 12345) if packet.SourceUserID != "user-1" { t.Errorf("SourceUserID = %s, want user-1", packet.SourceUserID) } if packet.ChannelID != "channel-1" { t.Errorf("ChannelID = %s, want channel-1", packet.ChannelID) } if packet.SequenceNum != 42 { t.Errorf("SequenceNum = %d, want 42", packet.SequenceNum) } if packet.Timestamp != 1000 { t.Errorf("Timestamp = %d, want 1000", packet.Timestamp) } if packet.SSRC != 5000 { t.Errorf("SSRC = %d, want 5000", packet.SSRC) } if packet.ClientTime != 12345 { t.Errorf("ClientTime = %d, want 12345", packet.ClientTime) } if string(packet.Payload) != "test audio" { t.Errorf("Payload = %s, want 'test audio'", string(packet.Payload)) } } func TestConcurrentPublish(t *testing.T) { router := NewRouter() channelID := "channel-1" receivedCount := 0 var mu sync.Mutex subscriber := func(p *Packet) error { mu.Lock() receivedCount++ mu.Unlock() return nil } router.Subscribe(channelID, subscriber) // Publish packets concurrently from multiple users done := make(chan bool, 10) for i := 0; i < 10; i++ { go func(userID string, seqNum uint32) { packet := NewPacket(userID, channelID, seqNum, uint32(1000+seqNum), 5000, []byte("audio"), 12345) router.PublishPacket(packet) done <- true }(("user-" + string(rune(i))), uint32(i)) } for i := 0; i < 10; i++ { <-done } if receivedCount != 10 { t.Errorf("Expected 10 received packets, got %d", receivedCount) } } func TestUnsubscribeNonexistent(t *testing.T) { router := NewRouter() channelID := "channel-1" subscriber := func(p *Packet) error { return nil } // Should not error when unsubscribing from nonexistent channel router.Unsubscribe(channelID, subscriber) // Should not error when unsubscribing nonexistent subscriber router.Subscribe(channelID, subscriber) router.Unsubscribe(channelID, func(p *Packet) error { return nil }) // Note: Unsubscribe is a placeholder, so count remains 1 count := router.GetSubscriberCount(channelID) if count != 1 { t.Errorf("Expected 1 subscriber (unsubscribe is placeholder), got %d", count) } }