Files
pekoe/internal/pubsub/pubsub_test.go
2026-04-03 00:09:40 +03:00

334 lines
7.2 KiB
Go

package pubsub
import (
"net"
"testing"
"time"
)
type mockConn struct {
data []byte
pos int
}
func (m *mockConn) Read(b []byte) (n int, err error) {
if m.pos >= len(m.data) {
return 0, nil
}
n = copy(b, m.data[m.pos:])
m.pos += n
return n, nil
}
func (m *mockConn) Write(b []byte) (n int, err error) {
m.data = append(m.data, b...)
return len(b), nil
}
func (m *mockConn) Close() error { return nil }
func (m *mockConn) LocalAddr() net.Addr { return nil }
func (m *mockConn) RemoteAddr() net.Addr { return nil }
func (m *mockConn) SetDeadline(time.Time) error { return nil }
func (m *mockConn) SetReadDeadline(time.Time) error { return nil }
func (m *mockConn) SetWriteDeadline(time.Time) error { return nil }
func NewMockClient() *Client {
return NewClient(&mockConn{data: []byte{}})
}
func TestNewHub(t *testing.T) {
hub := NewHub()
if hub == nil {
t.Fatal("NewHub() returned nil")
}
if hub.subs == nil {
t.Error("hub.subs is nil")
}
}
func TestHubSubscribe(t *testing.T) {
hub := NewHub()
client := NewMockClient()
// Subscribe to a channel
ok := hub.Subscribe(client, "news")
if !ok {
t.Error("Subscribe() returned false for new subscription")
}
// Check subscriber count
count := hub.ChannelCount("news")
if count != 1 {
t.Errorf("ChannelCount() = %d, want 1", count)
}
// Duplicate subscription should return false
ok = hub.Subscribe(client, "news")
if ok {
t.Error("Subscribe() should return false for duplicate subscription")
}
}
func TestHubUnsubscribe(t *testing.T) {
hub := NewHub()
client := NewMockClient()
hub.Subscribe(client, "news")
ok := hub.Unsubscribe(client, "news")
if !ok {
t.Error("Unsubscribe() returned false")
}
count := hub.ChannelCount("news")
if count != 0 {
t.Errorf("ChannelCount() = %d, want 0", count)
}
}
func TestHubUnsubscribeNotSubscribed(t *testing.T) {
hub := NewHub()
client := NewMockClient()
ok := hub.Unsubscribe(client, "nonexistent")
if ok {
t.Error("Unsubscribe() should return false for non-subscribed channel")
}
}
func TestHubUnsubscribeAll(t *testing.T) {
hub := NewHub()
client := NewMockClient()
hub.Subscribe(client, "news")
hub.Subscribe(client, "sports")
hub.Subscribe(client, "weather")
hub.UnsubscribeAll(client)
if hub.ChannelCount("news") != 0 {
t.Error("news channel should be empty")
}
if hub.ChannelCount("sports") != 0 {
t.Error("sports channel should be empty")
}
if hub.ChannelCount("weather") != 0 {
t.Error("weather channel should be empty")
}
}
func TestHubPublish(t *testing.T) {
hub := NewHub()
client1 := NewMockClient()
client2 := NewMockClient()
hub.Subscribe(client1, "news")
hub.Subscribe(client2, "news")
count := hub.Publish("news", []byte("Hello"))
if count != 2 {
t.Errorf("Publish() = %d, want 2", count)
}
}
func TestHubPublishEmptyChannel(t *testing.T) {
hub := NewHub()
count := hub.Publish("empty", []byte("Hello"))
if count != 0 {
t.Errorf("Publish() to empty channel = %d, want 0", count)
}
}
func TestHubChannelCount(t *testing.T) {
hub := NewHub()
client := NewMockClient()
if hub.ChannelCount("news") != 0 {
t.Error("new channel should have 0 subscribers")
}
hub.Subscribe(client, "news")
if hub.ChannelCount("news") != 1 {
t.Errorf("ChannelCount() = %d, want 1", hub.ChannelCount("news"))
}
hub.Subscribe(client, "news") // duplicate
if hub.ChannelCount("news") != 1 {
t.Errorf("ChannelCount() after duplicate = %d, want 1", hub.ChannelCount("news"))
}
}
func TestHubTotalChannels(t *testing.T) {
hub := NewHub()
client := NewMockClient()
if hub.TotalChannels() != 0 {
t.Errorf("TotalChannels() = %d, want 0", hub.TotalChannels())
}
hub.Subscribe(client, "news")
hub.Subscribe(client, "sports")
if hub.TotalChannels() != 2 {
t.Errorf("TotalChannels() = %d, want 2", hub.TotalChannels())
}
}
func TestHubChannelList(t *testing.T) {
hub := NewHub()
client := NewMockClient()
channels := hub.ChannelList("")
if len(channels) != 0 {
t.Errorf("Empty hub ChannelList() length = %d, want 0", len(channels))
}
hub.Subscribe(client, "news")
hub.Subscribe(client, "sports")
channels = hub.ChannelList("")
if len(channels) != 2 {
t.Errorf("ChannelList() length = %d, want 2", len(channels))
}
}
func TestHubMultipleClients(t *testing.T) {
hub := NewHub()
client1 := NewMockClient()
client2 := NewMockClient()
client3 := NewMockClient()
hub.Subscribe(client1, "news")
hub.Subscribe(client2, "news")
hub.Subscribe(client3, "news")
count := hub.ChannelCount("news")
if count != 3 {
t.Errorf("ChannelCount() = %d, want 3", count)
}
}
func TestHubChannelCleanup(t *testing.T) {
hub := NewHub()
client := NewMockClient()
hub.Subscribe(client, "temp")
if hub.ChannelCount("temp") != 1 {
t.Error("Channel should exist")
}
hub.Unsubscribe(client, "temp")
if hub.ChannelCount("temp") != 0 {
t.Error("Channel should be cleaned up")
}
channels := hub.ChannelList("")
for _, ch := range channels {
if ch == "temp" {
t.Error("Channel should not be in list after cleanup")
}
}
}
func TestNewClient(t *testing.T) {
conn := &mockConn{data: []byte{}}
client := NewClient(conn)
if client == nil {
t.Fatal("NewClient() returned nil")
}
if client.subscribed == nil {
t.Error("client.subscribed is nil")
}
}
func TestClientAddSubscription(t *testing.T) {
client := NewMockClient()
client.AddSubscription("news")
if client.SubsCount() != 1 {
t.Errorf("SubsCount() = %d, want 1", client.SubsCount())
}
client.AddSubscription("sports")
if client.SubsCount() != 2 {
t.Errorf("SubsCount() = %d, want 2", client.SubsCount())
}
}
func TestClientRemoveSubscription(t *testing.T) {
client := NewMockClient()
client.AddSubscription("news")
client.AddSubscription("sports")
client.RemoveSubscription("news")
if client.SubsCount() != 1 {
t.Errorf("SubsCount() = %d, want 1", client.SubsCount())
}
}
func TestClientGetChannels(t *testing.T) {
client := NewMockClient()
client.AddSubscription("news")
client.AddSubscription("sports")
channels := client.GetChannels()
if len(channels) != 2 {
t.Errorf("GetChannels() length = %d, want 2", len(channels))
}
found := make(map[string]bool)
for _, ch := range channels {
found[ch] = true
}
if !found["news"] || !found["sports"] {
t.Error("GetChannels() missing expected channels")
}
}
func TestClientGetChannelsReturnsCopy(t *testing.T) {
client := NewMockClient()
client.AddSubscription("news")
channels := client.GetChannels()
channels[0] = "modified"
channels2 := client.GetChannels()
if channels2[0] == "modified" {
t.Error("GetChannels() should return a copy, not modify original")
}
}
func TestClientSubsCount(t *testing.T) {
client := NewMockClient()
if client.SubsCount() != 0 {
t.Errorf("Initial SubsCount() = %d, want 0", client.SubsCount())
}
client.AddSubscription("news")
if client.SubsCount() != 1 {
t.Errorf("SubsCount() = %d, want 1", client.SubsCount())
}
}
func TestConcurrentSubscribe(t *testing.T) {
hub := NewHub()
client := NewMockClient()
done := make(chan bool)
go func() {
hub.Subscribe(client, "channel1")
done <- true
}()
hub.Subscribe(client, "channel2")
<-done
if hub.TotalChannels() != 2 {
t.Errorf("TotalChannels() = %d, want 2", hub.TotalChannels())
}
}