mirror of
https://github.com/HDT3213/godis.git
synced 2025-10-22 08:19:33 +08:00
add some unittests and bug fix
This commit is contained in:
@@ -7,8 +7,8 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// abstract of active client
|
||||
type Client struct {
|
||||
// Connection represents a connection with a redis-cli
|
||||
type Connection struct {
|
||||
conn net.Conn
|
||||
|
||||
// waiting util reply finished
|
||||
@@ -21,20 +21,23 @@ type Client struct {
|
||||
subs map[string]bool
|
||||
}
|
||||
|
||||
func (c *Client) Close() error {
|
||||
// Close disconnect with the client
|
||||
func (c *Connection) Close() error {
|
||||
c.waitingReply.WaitWithTimeout(10 * time.Second)
|
||||
_ = c.conn.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func MakeClient(conn net.Conn) *Client {
|
||||
return &Client{
|
||||
// NewConn creates Connection instance
|
||||
func NewConn(conn net.Conn) *Connection {
|
||||
return &Connection{
|
||||
conn: conn,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) Write(b []byte) error {
|
||||
if b == nil || len(b) == 0 {
|
||||
// Write sends response to client over tcp connection
|
||||
func (c *Connection) Write(b []byte) error {
|
||||
if len(b) == 0 {
|
||||
return nil
|
||||
}
|
||||
c.mu.Lock()
|
||||
@@ -44,7 +47,8 @@ func (c *Client) Write(b []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) SubsChannel(channel string) {
|
||||
// Subscribe add current connection into subscribers of the given channel
|
||||
func (c *Connection) Subscribe(channel string) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
@@ -54,7 +58,8 @@ func (c *Client) SubsChannel(channel string) {
|
||||
c.subs[channel] = true
|
||||
}
|
||||
|
||||
func (c *Client) UnSubsChannel(channel string) {
|
||||
// UnSubscribe removes current connection into subscribers of the given channel
|
||||
func (c *Connection) UnSubscribe(channel string) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
@@ -64,14 +69,16 @@ func (c *Client) UnSubsChannel(channel string) {
|
||||
delete(c.subs, channel)
|
||||
}
|
||||
|
||||
func (c *Client) SubsCount() int {
|
||||
// SubsCount returns the number of subscribing channels
|
||||
func (c *Connection) SubsCount() int {
|
||||
if c.subs == nil {
|
||||
return 0
|
||||
}
|
||||
return len(c.subs)
|
||||
}
|
||||
|
||||
func (c *Client) GetChannels() []string {
|
||||
// GetChannels returns all subscribing channels
|
||||
func (c *Connection) GetChannels() []string {
|
||||
if c.subs == nil {
|
||||
return make([]string, 0)
|
||||
}
|
@@ -24,12 +24,14 @@ var (
|
||||
UnknownErrReplyBytes = []byte("-ERR unknown\r\n")
|
||||
)
|
||||
|
||||
// Handler implements tcp.Handler and serves as a redis server
|
||||
type Handler struct {
|
||||
activeConn sync.Map // *client -> placeholder
|
||||
db db.DB
|
||||
closing atomic.AtomicBool // refusing new client and new request
|
||||
}
|
||||
|
||||
// MakeHandler creates a Handler instance
|
||||
func MakeHandler() *Handler {
|
||||
var db db.DB
|
||||
if config.Properties.Self != "" &&
|
||||
@@ -43,19 +45,20 @@ func MakeHandler() *Handler {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) closeClient(client *Client) {
|
||||
func (h *Handler) closeClient(client *Connection) {
|
||||
_ = client.Close()
|
||||
h.db.AfterClientClose(client)
|
||||
h.activeConn.Delete(client)
|
||||
}
|
||||
|
||||
// Handle receives and executes redis commands
|
||||
func (h *Handler) Handle(ctx context.Context, conn net.Conn) {
|
||||
if h.closing.Get() {
|
||||
// closing handler refuse new connection
|
||||
_ = conn.Close()
|
||||
}
|
||||
|
||||
client := MakeClient(conn)
|
||||
client := NewConn(conn)
|
||||
h.activeConn.Store(client, 1)
|
||||
|
||||
ch := parser.Parse(conn)
|
||||
@@ -98,12 +101,13 @@ func (h *Handler) Handle(ctx context.Context, conn net.Conn) {
|
||||
}
|
||||
}
|
||||
|
||||
// Close stops handler
|
||||
func (h *Handler) Close() error {
|
||||
logger.Info("handler shuting down...")
|
||||
h.closing.Set(true)
|
||||
// TODO: concurrent wait
|
||||
h.activeConn.Range(func(key interface{}, val interface{}) bool {
|
||||
client := key.(*Client)
|
||||
client := key.(*Connection)
|
||||
_ = client.Close()
|
||||
return true
|
||||
})
|
42
redis/server/server_test.go
Normal file
42
redis/server/server_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"github.com/hdt3213/godis/tcp"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestListenAndServe(t *testing.T) {
|
||||
var err error
|
||||
closeChan := make(chan struct{})
|
||||
listener, err := net.Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
addr := listener.Addr().String()
|
||||
go tcp.ListenAndServe(listener, MakeHandler(), closeChan)
|
||||
|
||||
conn, err := net.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
_, err = conn.Write([]byte("PING\r\n"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
bufReader := bufio.NewReader(conn)
|
||||
line, _, err := bufReader.ReadLine()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if string(line) != "+PONG" {
|
||||
t.Error("get wrong response")
|
||||
return
|
||||
}
|
||||
closeChan <- struct{}{}
|
||||
}
|
Reference in New Issue
Block a user