Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions resp/reply_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package resp

import (
"io"
"net"
"testing"
)

// TestReplyCommand tests the ReplyCommand function for
// all possible valid and invalid inputs
func TestReplyCommand(t *testing.T) {
tests := []struct {
reply []byte
want string
}{
{[]byte("+PONG\r\n"), "+PONG\r\n"},
{[]byte("+OK\r\n"), "+OK\r\n"},
{[]byte("$5\r\nhello\r\n"), "$5\r\nhello\r\n"},
{[]byte("-error message\r\n"), "-error message\r\n"},
}
for _, test := range tests {
server, client := net.Pipe()

ch := make(chan []byte, 1)
go func() {
b, _ := io.ReadAll(client)
ch <- b
}()

ReplyCommand(test.reply, server)
server.Close()

got := string(<-ch)
if got != test.want {
t.Errorf("ReplyCommand(%q) = %q; want %q", test.reply, got, test.want)
}
client.Close()
}
}

// TestReplyCommand_ClosedConn tests that ReplyCommand does not panic
// when the connection is already closed
func TestReplyCommand_ClosedConn(t *testing.T) {
server, client := net.Pipe()
client.Close()

defer func() {
if r := recover(); r != nil {
t.Errorf("ReplyCommand panicked on closed connection: %v", r)
}
}()
ReplyCommand([]byte("+PONG\r\n"), server)
server.Close()
}
62 changes: 62 additions & 0 deletions resp/request_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package resp

import (
"io"
"net"
"testing"
)

// newPipe returns a connected pair of net.Conn. server is passed to the function
// under test; client is used to read back what was written.
func newPipe(t *testing.T) (server, client net.Conn) {
t.Helper()
server, client = net.Pipe()
t.Cleanup(func() {
server.Close()
client.Close()
})
return
}

// readReply reads from the client side of the pipe in a goroutine and returns
// the bytes via a channel. The server side must be closed (or the write must
// complete) before this unblocks.
func readReply(client net.Conn) <-chan []byte {
ch := make(chan []byte, 1)
go func() {
b, _ := io.ReadAll(client)
ch <- b
}()
return ch
}

// TestPerformRequest tests the PerformRequest function for
// all possible valid and invalid inputs
func TestPerformRequest(t *testing.T) {
tests := []struct {
input []byte
want string
}{
// Valid commands
{[]byte("*1\r\n$4\r\nPING\r\n"), "+PONG\r\n"},
{[]byte("*2\r\n$4\r\nECHO\r\n$5\r\nhello\r\n"), "$5\r\nhello\r\n"},
// Invalid RESP prefix
{[]byte("%1\r\n$4\r\nPING\r\n"), "-invalid request\r\n"},
// Unknown command
{[]byte("*1\r\n$3\r\nFOO\r\n"), "-unsupported command\r\n"},
// nil buffer — ParseCommand returns zero-value Cmd with empty Name, nothing written
{nil, ""},
}
for _, test := range tests {
server, client := newPipe(t)
ch := readReply(client)

PerformRequest(test.input, server)
server.Close()

got := string(<-ch)
if got != test.want {
t.Errorf("PerformRequest(%q) = %q; want %q", test.input, got, test.want)
}
}
}
Loading