1047 lines
23 KiB
Go
1047 lines
23 KiB
Go
package server
|
|
|
|
import (
|
|
"bytes"
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/eleksir/pekoe/internal/config"
|
|
"github.com/eleksir/pekoe/internal/protocol"
|
|
"github.com/eleksir/pekoe/internal/pubsub"
|
|
)
|
|
|
|
type mockServerConn struct {
|
|
reader *bytes.Buffer
|
|
writer *bytes.Buffer
|
|
remote string
|
|
}
|
|
|
|
func newMockServerConn() *mockServerConn {
|
|
return &mockServerConn{
|
|
reader: bytes.NewBuffer([]byte{}),
|
|
writer: &bytes.Buffer{},
|
|
remote: "127.0.0.1:12345",
|
|
}
|
|
}
|
|
|
|
func (m *mockServerConn) Read(b []byte) (n int, err error) {
|
|
return m.reader.Read(b)
|
|
}
|
|
|
|
func (m *mockServerConn) Write(b []byte) (n int, err error) {
|
|
return m.writer.Write(b)
|
|
}
|
|
|
|
func (m *mockServerConn) Close() error { return nil }
|
|
func (m *mockServerConn) LocalAddr() net.Addr { return &mockAddr{"127.0.0.1:6379"} }
|
|
func (m *mockServerConn) RemoteAddr() net.Addr { return &mockAddr{m.remote} }
|
|
func (m *mockServerConn) SetDeadline(time.Time) error { return nil }
|
|
func (m *mockServerConn) SetReadDeadline(time.Time) error { return nil }
|
|
func (m *mockServerConn) SetWriteDeadline(time.Time) error { return nil }
|
|
|
|
type mockAddr struct {
|
|
s string
|
|
}
|
|
|
|
func (m *mockAddr) Network() string { return "tcp" }
|
|
func (m *mockAddr) String() string { return m.s }
|
|
|
|
type mockHub struct {
|
|
subs map[string]map[*pubsub.Client]struct{}
|
|
patterns map[string]map[*pubsub.Client]struct{}
|
|
clients map[uint64]*pubsub.Client
|
|
}
|
|
|
|
func newMockHub() *mockHub {
|
|
return &mockHub{
|
|
subs: make(map[string]map[*pubsub.Client]struct{}),
|
|
patterns: make(map[string]map[*pubsub.Client]struct{}),
|
|
clients: make(map[uint64]*pubsub.Client),
|
|
}
|
|
}
|
|
|
|
func (m *mockHub) Subscribe(client *pubsub.Client, channel string) bool {
|
|
if m.subs[channel] == nil {
|
|
m.subs[channel] = make(map[*pubsub.Client]struct{})
|
|
}
|
|
m.subs[channel][client] = struct{}{}
|
|
return true
|
|
}
|
|
|
|
func (m *mockHub) Unsubscribe(client *pubsub.Client, channel string) bool {
|
|
if m.subs[channel] != nil {
|
|
delete(m.subs[channel], client)
|
|
if len(m.subs[channel]) == 0 {
|
|
delete(m.subs, channel)
|
|
}
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (m *mockHub) UnsubscribeAll(client *pubsub.Client) {
|
|
for ch := range m.subs {
|
|
delete(m.subs[ch], client)
|
|
}
|
|
for p := range m.patterns {
|
|
delete(m.patterns[p], client)
|
|
}
|
|
}
|
|
|
|
func (m *mockHub) Publish(channel string, message []byte) int {
|
|
if m.subs[channel] == nil {
|
|
return 0
|
|
}
|
|
return len(m.subs[channel])
|
|
}
|
|
|
|
func (m *mockHub) PublishToPattern(channel string, message []byte) int {
|
|
if m.patterns == nil {
|
|
return 0
|
|
}
|
|
return len(m.patterns)
|
|
}
|
|
|
|
func (m *mockHub) PatternSubscribe(client *pubsub.Client, pattern string) (bool, error) {
|
|
if m.patterns[pattern] == nil {
|
|
m.patterns[pattern] = make(map[*pubsub.Client]struct{})
|
|
}
|
|
m.patterns[pattern][client] = struct{}{}
|
|
return true, nil
|
|
}
|
|
|
|
func (m *mockHub) PatternUnsubscribe(client *pubsub.Client, pattern string) bool {
|
|
if m.patterns[pattern] != nil {
|
|
delete(m.patterns[pattern], client)
|
|
if len(m.patterns[pattern]) == 0 {
|
|
delete(m.patterns, pattern)
|
|
}
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (m *mockHub) PatternCount() int {
|
|
if m.patterns == nil {
|
|
return 0
|
|
}
|
|
count := 0
|
|
for _, clients := range m.patterns {
|
|
count += len(clients)
|
|
}
|
|
return count
|
|
}
|
|
|
|
func (m *mockHub) ChannelCount(channel string) int {
|
|
if m.subs[channel] == nil {
|
|
return 0
|
|
}
|
|
return len(m.subs[channel])
|
|
}
|
|
|
|
func (m *mockHub) ChannelList(pattern string) []string {
|
|
channels := make([]string, 0, len(m.subs))
|
|
for ch := range m.subs {
|
|
if pattern == "" {
|
|
channels = append(channels, ch)
|
|
}
|
|
}
|
|
return channels
|
|
}
|
|
|
|
func (m *mockHub) TotalChannels() int {
|
|
return len(m.subs)
|
|
}
|
|
|
|
func (m *mockHub) RegisterClient(client *pubsub.Client) {
|
|
m.clients[client.ID()] = client
|
|
}
|
|
|
|
func (m *mockHub) UnregisterClient(client *pubsub.Client) {
|
|
delete(m.clients, client.ID())
|
|
}
|
|
|
|
func (m *mockHub) GetClient(id uint64) *pubsub.Client {
|
|
return m.clients[id]
|
|
}
|
|
|
|
func (m *mockHub) GetAllClients() []*pubsub.Client {
|
|
clients := make([]*pubsub.Client, 0, len(m.clients))
|
|
for _, c := range m.clients {
|
|
clients = append(clients, c)
|
|
}
|
|
return clients
|
|
}
|
|
|
|
func (m *mockHub) ClientCount() int {
|
|
return len(m.clients)
|
|
}
|
|
|
|
func TestNewServer(t *testing.T) {
|
|
cfg := &config.Config{
|
|
Bind: "127.0.0.1",
|
|
Port: 6379,
|
|
MaxClients: 100,
|
|
}
|
|
hub := newMockHub()
|
|
|
|
srv := New(cfg, hub)
|
|
if srv == nil {
|
|
t.Fatal("New() returned nil")
|
|
}
|
|
if srv.cfg == nil {
|
|
t.Error("srv.cfg is nil")
|
|
}
|
|
if srv.hub == nil {
|
|
t.Error("srv.hub is nil")
|
|
}
|
|
}
|
|
|
|
func TestServerAddr(t *testing.T) {
|
|
cfg := &config.Config{
|
|
Bind: "127.0.0.1",
|
|
Port: 6380,
|
|
}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
addr := srv.cfg.Addr()
|
|
if addr != "127.0.0.1:6380" {
|
|
t.Errorf("Addr() = %q, want 127.0.0.1:6380", addr)
|
|
}
|
|
}
|
|
|
|
func TestConnReader(t *testing.T) {
|
|
input := "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n"
|
|
conn := newMockServerConn()
|
|
conn.reader = bytes.NewBufferString(input)
|
|
r := NewConnReader(conn, 1024)
|
|
|
|
cmd, err := r.ReadCommand()
|
|
if err != nil {
|
|
t.Fatalf("ReadCommand() error: %v", err)
|
|
}
|
|
if len(cmd.Args) != 2 {
|
|
t.Errorf("len(Args) = %d, want 2", len(cmd.Args))
|
|
}
|
|
if string(cmd.Args[0]) != "foo" {
|
|
t.Errorf("Args[0] = %q, want foo", string(cmd.Args[0]))
|
|
}
|
|
if string(cmd.Args[1]) != "bar" {
|
|
t.Errorf("Args[1] = %q, want bar", string(cmd.Args[1]))
|
|
}
|
|
}
|
|
|
|
func TestConnReaderEmptyCommand(t *testing.T) {
|
|
input := "*0\r\n"
|
|
conn := newMockServerConn()
|
|
conn.reader = bytes.NewBufferString(input)
|
|
r := NewConnReader(conn, 1024)
|
|
|
|
_, err := r.ReadCommand()
|
|
if err == nil {
|
|
t.Error("Expected error for empty command")
|
|
}
|
|
}
|
|
|
|
func TestConnWriterWriteStatus(t *testing.T) {
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
w.WriteStatus("OK")
|
|
_ = w.Flush()
|
|
|
|
if conn.writer.String() != "+OK\r\n" {
|
|
t.Errorf("WriteStatus() = %q, want +OK\\r\\n", conn.writer.String())
|
|
}
|
|
}
|
|
|
|
func TestConnWriterWriteError(t *testing.T) {
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
w.WriteError("ERR test error")
|
|
_ = w.Flush()
|
|
|
|
if conn.writer.String() != "-ERR test error\r\n" {
|
|
t.Errorf("WriteError() = %q, want -ERR test error\\r\\n", conn.writer.String())
|
|
}
|
|
}
|
|
|
|
func TestConnWriterWriteInt(t *testing.T) {
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
w.WriteInt(42)
|
|
_ = w.Flush()
|
|
|
|
if conn.writer.String() != ":42\r\n" {
|
|
t.Errorf("WriteInt() = %q, want :42\\r\\n", conn.writer.String())
|
|
}
|
|
}
|
|
|
|
func TestConnWriterWriteBulk(t *testing.T) {
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
w.WriteBulk([]byte("hello"))
|
|
_ = w.Flush()
|
|
|
|
if conn.writer.String() != "$5\r\nhello\r\n" {
|
|
t.Errorf("WriteBulk() = %q, want $5\\r\\nhello\\r\\n", conn.writer.String())
|
|
}
|
|
}
|
|
|
|
func TestConnWriterWriteArray(t *testing.T) {
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
w.WriteArray([]protocol.Value{
|
|
protocol.Bulk("message"),
|
|
protocol.Bulk("news"),
|
|
protocol.Bulk("hello"),
|
|
})
|
|
_ = w.Flush()
|
|
|
|
if conn.writer.Len() == 0 {
|
|
t.Error("WriteArray() produced empty output")
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandEmpty(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
err := srv.processCommand(nil, &Command{Args: [][]byte{}}, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand() error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandSubscribe(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
client := pubsub.NewClient(newMockServerConn())
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("subscribe"), []byte("news")},
|
|
}
|
|
|
|
err := srv.processCommand(client, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand() error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandUnsubscribe(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
client := pubsub.NewClient(newMockServerConn())
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("unsubscribe"), []byte("news")},
|
|
}
|
|
|
|
err := srv.processCommand(client, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand() error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandPublish(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("publish"), []byte("news"), []byte("Hello")},
|
|
}
|
|
|
|
err := srv.processCommand(nil, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand() error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandPublishWrongArgs(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("publish"), []byte("news")},
|
|
}
|
|
|
|
err := srv.processCommand(nil, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand() error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandPubsubNumsub(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("pubsub"), []byte("numsub"), []byte("news")},
|
|
}
|
|
|
|
err := srv.processCommand(nil, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand() error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandPubsubChannels(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("pubsub"), []byte("channels")},
|
|
}
|
|
|
|
err := srv.processCommand(nil, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand() error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandPubsubNumpat(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("pubsub"), []byte("numpat")},
|
|
}
|
|
|
|
err := srv.processCommand(nil, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand() error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandUnknown(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("unknowncmd")},
|
|
}
|
|
|
|
err := srv.processCommand(nil, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand() error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandPsubscribeNotImplemented(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
client := pubsub.NewClient(newMockServerConn())
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("psubscribe"), []byte("news*")},
|
|
}
|
|
|
|
err := srv.processCommand(client, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand() error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestHandleSubscribe(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
client := pubsub.NewClient(newMockServerConn())
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
err := srv.handleSubscribe(client, [][]byte{[]byte("news"), []byte("sports")}, w)
|
|
if err != nil {
|
|
t.Errorf("handleSubscribe() error: %v", err)
|
|
}
|
|
|
|
if hub.ChannelCount("news") != 1 {
|
|
t.Errorf("news channel count = %d, want 1", hub.ChannelCount("news"))
|
|
}
|
|
if hub.ChannelCount("sports") != 1 {
|
|
t.Errorf("sports channel count = %d, want 1", hub.ChannelCount("sports"))
|
|
}
|
|
}
|
|
|
|
func TestHandleSubscribeNoChannels(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
client := pubsub.NewClient(newMockServerConn())
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
err := srv.handleSubscribe(client, [][]byte{}, w)
|
|
if err != nil {
|
|
t.Errorf("handleSubscribe() error: %v", err)
|
|
}
|
|
|
|
_ = w.Flush()
|
|
|
|
if conn.writer.Len() == 0 {
|
|
t.Error("Expected error response written to connection")
|
|
}
|
|
}
|
|
|
|
func TestHandleUnsubscribe(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
client := pubsub.NewClient(newMockServerConn())
|
|
hub.Subscribe(client, "news")
|
|
hub.Subscribe(client, "sports")
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
err := srv.handleUnsubscribe(client, [][]byte{[]byte("news")}, w)
|
|
if err != nil {
|
|
t.Errorf("handleUnsubscribe() error: %v", err)
|
|
}
|
|
|
|
if hub.ChannelCount("news") != 0 {
|
|
t.Errorf("news channel count = %d, want 0", hub.ChannelCount("news"))
|
|
}
|
|
if hub.ChannelCount("sports") != 1 {
|
|
t.Errorf("sports channel count = %d, want 1", hub.ChannelCount("sports"))
|
|
}
|
|
}
|
|
|
|
func TestHandleUnsubscribeAll(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
client := pubsub.NewClient(newMockServerConn())
|
|
client.AddSubscription("news")
|
|
client.AddSubscription("sports")
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
err := srv.handleUnsubscribe(client, [][]byte{}, w)
|
|
if err != nil {
|
|
t.Errorf("handleUnsubscribe() error: %v", err)
|
|
}
|
|
|
|
if hub.TotalChannels() != 0 {
|
|
t.Errorf("TotalChannels() = %d, want 0", hub.TotalChannels())
|
|
}
|
|
}
|
|
|
|
func TestHandlePublish(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
client := pubsub.NewClient(newMockServerConn())
|
|
hub.Subscribe(client, "news")
|
|
hub.Subscribe(client, "news")
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
err := srv.handlePublish([][]byte{[]byte("news"), []byte("Hello")}, w)
|
|
if err != nil {
|
|
t.Errorf("handlePublish() error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestHandlePublishWrongArgs(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
err := srv.handlePublish([][]byte{[]byte("news")}, w)
|
|
if err != nil {
|
|
t.Errorf("handlePublish() error: %v", err)
|
|
}
|
|
|
|
_ = w.Flush()
|
|
|
|
if conn.writer.Len() == 0 {
|
|
t.Error("Expected error response written to connection")
|
|
}
|
|
}
|
|
|
|
func TestHandlePubsubNoArgs(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
err := srv.handlePubsub([][]byte{}, w)
|
|
if err != nil {
|
|
t.Errorf("handlePubsub() error: %v", err)
|
|
}
|
|
|
|
_ = w.Flush()
|
|
|
|
if conn.writer.Len() == 0 {
|
|
t.Error("Expected error response written to connection")
|
|
}
|
|
}
|
|
|
|
func TestHandlePubsubUnknownSubcommand(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
err := srv.handlePubsub([][]byte{[]byte("unknown")}, w)
|
|
if err != nil {
|
|
t.Errorf("handlePubsub() error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCommandStruct(t *testing.T) {
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("subscribe"), []byte("channel1")},
|
|
}
|
|
if len(cmd.Args) != 2 {
|
|
t.Errorf("len(Args) = %d, want 2", len(cmd.Args))
|
|
}
|
|
}
|
|
|
|
func TestChannelList(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
client := pubsub.NewClient(newMockServerConn())
|
|
hub.Subscribe(client, "news")
|
|
hub.Subscribe(client, "sports")
|
|
|
|
channels := srv.channelList("")
|
|
if len(channels) != 2 {
|
|
t.Errorf("channelList() = %v, want 2 channels", channels)
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandQuit(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("quit")},
|
|
}
|
|
|
|
err := srv.processCommand(nil, cmd, w)
|
|
if err != ErrQuit {
|
|
t.Errorf("processCommand(QUIT) error = %v, want ErrQuit", err)
|
|
}
|
|
|
|
_ = w.Flush()
|
|
|
|
// Verify OK response was written
|
|
if conn.writer.String() != "+OK\r\n" {
|
|
t.Errorf("QUIT response = %q, want +OK\\r\\n", conn.writer.String())
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandQuitCaseInsensitive(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("QUIT")},
|
|
}
|
|
|
|
err := srv.processCommand(nil, cmd, w)
|
|
if err != ErrQuit {
|
|
t.Errorf("processCommand(QUIT) error = %v, want ErrQuit", err)
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandClientId(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
client := pubsub.NewClient(newMockServerConn())
|
|
hub.RegisterClient(client)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("client"), []byte("id")},
|
|
}
|
|
|
|
err := srv.processCommand(client, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand(CLIENT ID) error = %v", err)
|
|
}
|
|
|
|
_ = w.Flush()
|
|
|
|
// Should return the client's ID
|
|
output := conn.writer.String()
|
|
if output == "" {
|
|
t.Error("CLIENT ID returned empty response")
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandClientSetname(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
client := pubsub.NewClient(newMockServerConn())
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("client"), []byte("setname"), []byte("myconn")},
|
|
}
|
|
|
|
err := srv.processCommand(client, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand(CLIENT SETNAME) error = %v", err)
|
|
}
|
|
|
|
_ = w.Flush()
|
|
|
|
if conn.writer.String() != "+OK\r\n" {
|
|
t.Errorf("CLIENT SETNAME response = %q, want +OK", conn.writer.String())
|
|
}
|
|
|
|
if client.GetName() != "myconn" {
|
|
t.Errorf("Client name = %q, want 'myconn'", client.GetName())
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandClientGetname(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
client := pubsub.NewClient(newMockServerConn())
|
|
client.SetName("testname")
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("client"), []byte("getname")},
|
|
}
|
|
|
|
err := srv.processCommand(client, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand(CLIENT GETNAME) error = %v", err)
|
|
}
|
|
|
|
_ = w.Flush()
|
|
|
|
// Should return the name
|
|
output := conn.writer.String()
|
|
if output == "" {
|
|
t.Error("CLIENT GETNAME returned empty response")
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandClientGetnameNoName(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
client := pubsub.NewClient(newMockServerConn())
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("client"), []byte("getname")},
|
|
}
|
|
|
|
err := srv.processCommand(client, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand(CLIENT GETNAME) error = %v", err)
|
|
}
|
|
|
|
_ = w.Flush()
|
|
|
|
// Should return nil (null bulk string)
|
|
output := conn.writer.String()
|
|
if output != "$-1\r\n" {
|
|
t.Errorf("CLIENT GETNAME response = %q, want $-1", output)
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandClientList(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
client := pubsub.NewClient(newMockServerConn())
|
|
hub.RegisterClient(client)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("client"), []byte("list")},
|
|
}
|
|
|
|
err := srv.processCommand(client, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand(CLIENT LIST) error = %v", err)
|
|
}
|
|
|
|
_ = w.Flush()
|
|
|
|
// Should contain client info
|
|
output := conn.writer.String()
|
|
if output == "" {
|
|
t.Error("CLIENT LIST returned empty response")
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandClientInfo(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
client := pubsub.NewClient(newMockServerConn())
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("client"), []byte("info")},
|
|
}
|
|
|
|
err := srv.processCommand(client, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand(CLIENT INFO) error = %v", err)
|
|
}
|
|
|
|
_ = w.Flush()
|
|
|
|
// Should contain client info
|
|
output := conn.writer.String()
|
|
if output == "" {
|
|
t.Error("CLIENT INFO returned empty response")
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandClientPause(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("client"), []byte("pause"), []byte("1000")},
|
|
}
|
|
|
|
err := srv.processCommand(nil, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand(CLIENT PAUSE) error = %v", err)
|
|
}
|
|
|
|
_ = w.Flush()
|
|
|
|
if conn.writer.String() != "+OK\r\n" {
|
|
t.Errorf("CLIENT PAUSE response = %q, want +OK", conn.writer.String())
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandClientUnpause(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("client"), []byte("unpause")},
|
|
}
|
|
|
|
err := srv.processCommand(nil, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand(CLIENT UNPAUSE) error = %v", err)
|
|
}
|
|
|
|
_ = w.Flush()
|
|
|
|
if conn.writer.String() != "+OK\r\n" {
|
|
t.Errorf("CLIENT UNPAUSE response = %q, want +OK", conn.writer.String())
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandClientReply(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
client := pubsub.NewClient(newMockServerConn())
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("client"), []byte("reply"), []byte("skip")},
|
|
}
|
|
|
|
err := srv.processCommand(client, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand(CLIENT REPLY) error = %v", err)
|
|
}
|
|
|
|
_ = w.Flush()
|
|
|
|
if conn.writer.String() != "+OK\r\n" {
|
|
t.Errorf("CLIENT REPLY response = %q, want +OK", conn.writer.String())
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandClientTracking(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("client"), []byte("tracking"), []byte("on")},
|
|
}
|
|
|
|
err := srv.processCommand(nil, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand(CLIENT TRACKING) error = %v", err)
|
|
}
|
|
|
|
_ = w.Flush()
|
|
|
|
if conn.writer.String() != "+OK\r\n" {
|
|
t.Errorf("CLIENT TRACKING response = %q, want +OK", conn.writer.String())
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandClientNoArgs(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("client")},
|
|
}
|
|
|
|
err := srv.processCommand(nil, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand(CLIENT) error = %v", err)
|
|
}
|
|
|
|
_ = w.Flush()
|
|
|
|
// Should return error
|
|
output := conn.writer.String()
|
|
if output == "" {
|
|
t.Error("CLIENT without args should return error")
|
|
}
|
|
}
|
|
|
|
func TestProcessCommandClientUnknownSubcommand(t *testing.T) {
|
|
cfg := &config.Config{Bind: "127.0.0.1", Port: 6379}
|
|
hub := newMockHub()
|
|
srv := New(cfg, hub)
|
|
|
|
conn := newMockServerConn()
|
|
w := NewConnWriter(conn)
|
|
|
|
cmd := &Command{
|
|
Args: [][]byte{[]byte("client"), []byte("unknowncmd")},
|
|
}
|
|
|
|
err := srv.processCommand(nil, cmd, w)
|
|
if err != nil {
|
|
t.Errorf("processCommand(CLIENT unknowncmd) error = %v", err)
|
|
}
|
|
|
|
_ = w.Flush()
|
|
|
|
// Should return error
|
|
output := conn.writer.String()
|
|
if output == "" {
|
|
t.Error("CLIENT unknown subcommand should return error")
|
|
}
|
|
}
|