add unittests and bug fix

This commit is contained in:
hdt3213
2021-05-05 20:51:53 +08:00
parent f1ab47bd83
commit 18d2cbb29b
30 changed files with 704 additions and 446 deletions

View File

@@ -8,8 +8,5 @@ before_install:
- sudo apt-get install redis-server; redis-server & - sudo apt-get install redis-server; redis-server &
- go get github.com/mattn/goveralls - go get github.com/mattn/goveralls
script: script:
- go test -coverprofile=coverage.txt -covermode=atomic ./... - go test -covermode=atomic ./...
- $GOPATH/bin/goveralls -service=travis-ci - $GOPATH/bin/goveralls -service=travis-ci
after_success:
- bash <(curl -s https://codecov.io/bash)

View File

@@ -70,8 +70,8 @@ func MakeCluster() *Cluster {
return cluster return cluster
} }
// args contains all // CmdFunc represents the handler of a redis command
type CmdFunc func(cluster *Cluster, c redis.Connection, args [][]byte) redis.Reply type CmdFunc func(cluster *Cluster, c redis.Connection, cmdAndArgs [][]byte) redis.Reply
func (cluster *Cluster) Close() { func (cluster *Cluster) Close() {
cluster.db.Close() cluster.db.Close()

View File

@@ -19,20 +19,11 @@ var (
// broadcast msg to all peers in cluster when receive publish command from client // broadcast msg to all peers in cluster when receive publish command from client
func Publish(cluster *Cluster, c redis.Connection, args [][]byte) redis.Reply { func Publish(cluster *Cluster, c redis.Connection, args [][]byte) redis.Reply {
var count int64 = 0 var count int64 = 0
for _, peer := range cluster.nodes { results := cluster.Broadcast(c, args)
var re redis.Reply for _, val := range results {
if peer == cluster.self { if errReply, ok := val.(reply.ErrorReply); ok {
args0 := make([][]byte, len(args))
copy(args0, args)
args0[0] = publishCmd
re = cluster.db.Exec(c, args0) // let local db.hub handle publish
} else {
args[0] = publishRelayCmd
re = cluster.Relay(peer, c, args)
}
if errReply, ok := re.(reply.ErrorReply); ok {
logger.Error("publish occurs error: " + errReply.Error()) logger.Error("publish occurs error: " + errReply.Error())
} else if intReply, ok := re.(*reply.IntReply); ok { } else if intReply, ok := val.(*reply.IntReply); ok {
count += intReply.Code count += intReply.Code
} }
} }

48
cluster/pubsub_test.go Normal file
View File

@@ -0,0 +1,48 @@
package cluster
import (
"github.com/hdt3213/godis/lib/utils"
"github.com/hdt3213/godis/redis/connection"
"github.com/hdt3213/godis/redis/parser"
"github.com/hdt3213/godis/redis/reply/asserts"
"testing"
)
func TestPublish(t *testing.T) {
channel := utils.RandString(5)
msg := utils.RandString(5)
conn := &connection.FakeConn{}
Subscribe(testCluster, conn, utils.ToBytesList("SUBSCRIBE", channel))
conn.Clean() // clean subscribe success
Publish(testCluster, conn, utils.ToBytesList("PUBLISH", channel, msg))
data := conn.Bytes()
ret, err := parser.ParseOne(data)
if err != nil {
t.Error(err)
return
}
asserts.AssertMultiBulkReply(t, ret, []string{
"message",
channel,
msg,
})
// unsubscribe
UnSubscribe(testCluster, conn, utils.ToBytesList("UNSUBSCRIBE", channel))
conn.Clean()
Publish(testCluster, conn, utils.ToBytesList("PUBLISH", channel, msg))
data = conn.Bytes()
if len(data) > 0 {
t.Error("expect no msg")
}
// unsubscribe all
Subscribe(testCluster, conn, utils.ToBytesList("SUBSCRIBE", channel))
UnSubscribe(testCluster, conn, utils.ToBytesList("UNSUBSCRIBE"))
conn.Clean()
Publish(testCluster, conn, utils.ToBytesList("PUBLISH", channel, msg))
data = conn.Bytes()
if len(data) > 0 {
t.Error("expect no msg")
}
}

View File

@@ -82,7 +82,7 @@ func (db *DB) loadAof(maxBytes int) {
defer file.Close() defer file.Close()
reader := utils.NewLimitedReader(file, maxBytes) reader := utils.NewLimitedReader(file, maxBytes)
ch := parser.Parse(reader) ch := parser.ParseStream(reader)
for p := range ch { for p := range ch {
if p.Err != nil { if p.Err != nil {
if p.Err == io.EOF { if p.Err == io.EOF {

View File

@@ -3,6 +3,8 @@ package db
import ( import (
"github.com/hdt3213/godis/config" "github.com/hdt3213/godis/config"
"github.com/hdt3213/godis/datastruct/utils" "github.com/hdt3213/godis/datastruct/utils"
utils2 "github.com/hdt3213/godis/lib/utils"
"github.com/hdt3213/godis/redis/reply"
"io/ioutil" "io/ioutil"
"os" "os"
"path" "path"
@@ -32,31 +34,31 @@ func TestAof(t *testing.T) {
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
key := strconv.Itoa(cursor) key := strconv.Itoa(cursor)
cursor++ cursor++
Set(aofWriteDB, toArgs(key, RandString(8), "EX", "10000")) Set(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8), "EX", "10000"))
keys = append(keys, key) keys = append(keys, key)
} }
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
key := strconv.Itoa(cursor) key := strconv.Itoa(cursor)
cursor++ cursor++
RPush(aofWriteDB, toArgs(key, RandString(8))) RPush(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
keys = append(keys, key) keys = append(keys, key)
} }
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
key := strconv.Itoa(cursor) key := strconv.Itoa(cursor)
cursor++ cursor++
HSet(aofWriteDB, toArgs(key, RandString(8), RandString(8))) HSet(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8), utils2.RandString(8)))
keys = append(keys, key) keys = append(keys, key)
} }
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
key := strconv.Itoa(cursor) key := strconv.Itoa(cursor)
cursor++ cursor++
SAdd(aofWriteDB, toArgs(key, RandString(8))) SAdd(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
keys = append(keys, key) keys = append(keys, key)
} }
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
key := strconv.Itoa(cursor) key := strconv.Itoa(cursor)
cursor++ cursor++
ZAdd(aofWriteDB, toArgs(key, "10", RandString(8))) ZAdd(aofWriteDB, utils2.ToBytesList(key, "10", utils2.RandString(8)))
keys = append(keys, key) keys = append(keys, key)
} }
aofWriteDB.Close() // wait for aof finished aofWriteDB.Close() // wait for aof finished
@@ -98,41 +100,49 @@ func TestRewriteAOF(t *testing.T) {
aofWriteDB := MakeDB() aofWriteDB := MakeDB()
size := 1 size := 1
keys := make([]string, 0) keys := make([]string, 0)
ttlKeys := make([]string, 0)
cursor := 0 cursor := 0
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
key := "str" + strconv.Itoa(cursor) key := "str" + strconv.Itoa(cursor)
cursor++ cursor++
Set(aofWriteDB, toArgs(key, RandString(8))) Set(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
Set(aofWriteDB, toArgs(key, RandString(8))) Set(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
keys = append(keys, key) keys = append(keys, key)
} }
// test ttl
for i := 0; i < size; i++ {
key := "str" + strconv.Itoa(cursor)
cursor++
Set(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8), "EX", "1000"))
ttlKeys = append(ttlKeys, key)
}
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
key := "list" + strconv.Itoa(cursor) key := "list" + strconv.Itoa(cursor)
cursor++ cursor++
RPush(aofWriteDB, toArgs(key, RandString(8))) RPush(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
RPush(aofWriteDB, toArgs(key, RandString(8))) RPush(aofWriteDB, utils2.ToBytesList(key, utils2.RandString(8)))
keys = append(keys, key) keys = append(keys, key)
} }
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
key := "hash" + strconv.Itoa(cursor) key := "hash" + strconv.Itoa(cursor)
cursor++ cursor++
field := RandString(8) field := utils2.RandString(8)
HSet(aofWriteDB, toArgs(key, field, RandString(8))) HSet(aofWriteDB, utils2.ToBytesList(key, field, utils2.RandString(8)))
HSet(aofWriteDB, toArgs(key, field, RandString(8))) HSet(aofWriteDB, utils2.ToBytesList(key, field, utils2.RandString(8)))
keys = append(keys, key) keys = append(keys, key)
} }
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
key := "set" + strconv.Itoa(cursor) key := "set" + strconv.Itoa(cursor)
cursor++ cursor++
member := RandString(8) member := utils2.RandString(8)
SAdd(aofWriteDB, toArgs(key, member)) SAdd(aofWriteDB, utils2.ToBytesList(key, member))
SAdd(aofWriteDB, toArgs(key, member)) SAdd(aofWriteDB, utils2.ToBytesList(key, member))
keys = append(keys, key) keys = append(keys, key)
} }
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
key := "zset" + strconv.Itoa(cursor) key := "zset" + strconv.Itoa(cursor)
cursor++ cursor++
ZAdd(aofWriteDB, toArgs(key, "10", RandString(8))) ZAdd(aofWriteDB, utils2.ToBytesList(key, "10", utils2.RandString(8)))
keys = append(keys, key) keys = append(keys, key)
} }
time.Sleep(time.Second) // wait for async goroutine finish its job time.Sleep(time.Second) // wait for async goroutine finish its job
@@ -156,5 +166,16 @@ func TestRewriteAOF(t *testing.T) {
t.Errorf("wrong value of key: %s", key) t.Errorf("wrong value of key: %s", key)
} }
} }
for _, key := range ttlKeys {
ret := TTL(aofReadDB, utils2.ToBytesList(key))
intResult, ok := ret.(*reply.IntReply)
if !ok {
t.Errorf("expected int reply, actually %s", ret.ToBytes())
return
}
if intResult.Code <= 0 {
t.Errorf("expect a positive integer, actual: %d", intResult.Code)
}
}
aofReadDB.Close() aofReadDB.Close()
} }

View File

@@ -2,6 +2,7 @@ package db
import ( import (
"fmt" "fmt"
"github.com/hdt3213/godis/lib/utils"
"github.com/hdt3213/godis/redis/reply" "github.com/hdt3213/godis/redis/reply"
"github.com/hdt3213/godis/redis/reply/asserts" "github.com/hdt3213/godis/redis/reply/asserts"
"strconv" "strconv"
@@ -9,52 +10,52 @@ import (
) )
func TestGeoHash(t *testing.T) { func TestGeoHash(t *testing.T) {
FlushDB(testDB, toArgs()) FlushDB(testDB, utils.ToBytesList())
key := RandString(10) key := utils.RandString(10)
pos := RandString(10) pos := utils.RandString(10)
result := GeoAdd(testDB, toArgs(key, "13.361389", "38.115556", pos)) result := GeoAdd(testDB, utils.ToBytesList(key, "13.361389", "38.115556", pos))
asserts.AssertIntReply(t, result, 1) asserts.AssertIntReply(t, result, 1)
result = GeoHash(testDB, toArgs(key, pos)) result = GeoHash(testDB, utils.ToBytesList(key, pos))
asserts.AssertMultiBulkReply(t, result, []string{"sqc8b49rnys00"}) asserts.AssertMultiBulkReply(t, result, []string{"sqc8b49rnys00"})
} }
func TestGeoRadius(t *testing.T) { func TestGeoRadius(t *testing.T) {
FlushDB(testDB, toArgs()) FlushDB(testDB, utils.ToBytesList())
key := RandString(10) key := utils.RandString(10)
pos1 := RandString(10) pos1 := utils.RandString(10)
pos2 := RandString(10) pos2 := utils.RandString(10)
GeoAdd(testDB, toArgs(key, GeoAdd(testDB, utils.ToBytesList(key,
"13.361389", "38.115556", pos1, "13.361389", "38.115556", pos1,
"15.087269", "37.502669", pos2, "15.087269", "37.502669", pos2,
)) ))
result := GeoRadius(testDB, toArgs(key, "15", "37", "200", "km")) result := GeoRadius(testDB, utils.ToBytesList(key, "15", "37", "200", "km"))
asserts.AssertMultiBulkReplySize(t, result, 2) asserts.AssertMultiBulkReplySize(t, result, 2)
} }
func TestGeoRadiusByMember(t *testing.T) { func TestGeoRadiusByMember(t *testing.T) {
FlushDB(testDB, toArgs()) FlushDB(testDB, utils.ToBytesList())
key := RandString(10) key := utils.RandString(10)
pos1 := RandString(10) pos1 := utils.RandString(10)
pos2 := RandString(10) pos2 := utils.RandString(10)
pivot := RandString(10) pivot := utils.RandString(10)
GeoAdd(testDB, toArgs(key, GeoAdd(testDB, utils.ToBytesList(key,
"13.361389", "38.115556", pos1, "13.361389", "38.115556", pos1,
"17.087269", "38.502669", pos2, "17.087269", "38.502669", pos2,
"13.583333", "37.316667", pivot, "13.583333", "37.316667", pivot,
)) ))
result := GeoRadiusByMember(testDB, toArgs(key, pivot, "100", "km")) result := GeoRadiusByMember(testDB, utils.ToBytesList(key, pivot, "100", "km"))
asserts.AssertMultiBulkReplySize(t, result, 2) asserts.AssertMultiBulkReplySize(t, result, 2)
} }
func TestGeoPos(t *testing.T) { func TestGeoPos(t *testing.T) {
FlushDB(testDB, toArgs()) FlushDB(testDB, utils.ToBytesList())
key := RandString(10) key := utils.RandString(10)
pos1 := RandString(10) pos1 := utils.RandString(10)
pos2 := RandString(10) pos2 := utils.RandString(10)
GeoAdd(testDB, toArgs(key, GeoAdd(testDB, utils.ToBytesList(key,
"13.361389", "38.115556", pos1, "13.361389", "38.115556", pos1,
)) ))
result := GeoPos(testDB, toArgs(key, pos1, pos2)) result := GeoPos(testDB, utils.ToBytesList(key, pos1, pos2))
expected := "*2\r\n*2\r\n$18\r\n13.361386698670685\r\n$17\r\n38.11555536696687\r\n*0\r\n" expected := "*2\r\n*2\r\n$18\r\n13.361386698670685\r\n$17\r\n38.11555536696687\r\n*0\r\n"
if string(result.ToBytes()) != expected { if string(result.ToBytes()) != expected {
t.Error("test failed") t.Error("test failed")
@@ -62,15 +63,15 @@ func TestGeoPos(t *testing.T) {
} }
func TestGeoDist(t *testing.T) { func TestGeoDist(t *testing.T) {
FlushDB(testDB, toArgs()) FlushDB(testDB, utils.ToBytesList())
key := RandString(10) key := utils.RandString(10)
pos1 := RandString(10) pos1 := utils.RandString(10)
pos2 := RandString(10) pos2 := utils.RandString(10)
GeoAdd(testDB, toArgs(key, GeoAdd(testDB, utils.ToBytesList(key,
"13.361389", "38.115556", pos1, "13.361389", "38.115556", pos1,
"15.087269", "37.502669", pos2, "15.087269", "37.502669", pos2,
)) ))
result := GeoDist(testDB, toArgs(key, pos1, pos2, "km")) result := GeoDist(testDB, utils.ToBytesList(key, pos1, pos2, "km"))
bulkReply, ok := result.(*reply.BulkReply) bulkReply, ok := result.(*reply.BulkReply)
if !ok { if !ok {
t.Error(fmt.Sprintf("expected bulk reply, actually %s", result.ToBytes())) t.Error(fmt.Sprintf("expected bulk reply, actually %s", result.ToBytes()))

View File

@@ -3,6 +3,7 @@ package db
import ( import (
"fmt" "fmt"
"github.com/hdt3213/godis/datastruct/utils" "github.com/hdt3213/godis/datastruct/utils"
utils2 "github.com/hdt3213/godis/lib/utils"
"github.com/hdt3213/godis/redis/reply" "github.com/hdt3213/godis/redis/reply"
"github.com/hdt3213/godis/redis/reply/asserts" "github.com/hdt3213/godis/redis/reply/asserts"
"strconv" "strconv"
@@ -14,13 +15,13 @@ func TestHSet(t *testing.T) {
size := 100 size := 100
// test hset // test hset
key := RandString(10) key := utils2.RandString(10)
values := make(map[string][]byte, size) values := make(map[string][]byte, size)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
value := RandString(10) value := utils2.RandString(10)
field := strconv.Itoa(i) field := strconv.Itoa(i)
values[field] = []byte(value) values[field] = []byte(value)
result := HSet(testDB, toArgs(key, field, value)) result := HSet(testDB, utils2.ToBytesList(key, field, value))
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(1) { if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(1) {
t.Error(fmt.Sprintf("expected %d, actually %d", 1, intResult.Code)) t.Error(fmt.Sprintf("expected %d, actually %d", 1, intResult.Code))
} }
@@ -28,19 +29,19 @@ func TestHSet(t *testing.T) {
// test hget and hexists // test hget and hexists
for field, v := range values { for field, v := range values {
actual := HGet(testDB, toArgs(key, field)) actual := HGet(testDB, utils2.ToBytesList(key, field))
expected := reply.MakeBulkReply(v) expected := reply.MakeBulkReply(v)
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(actual.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(actual.ToBytes())))
} }
actual = HExists(testDB, toArgs(key, field)) actual = HExists(testDB, utils2.ToBytesList(key, field))
if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(1) { if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(1) {
t.Error(fmt.Sprintf("expected %d, actually %d", 1, intResult.Code)) t.Error(fmt.Sprintf("expected %d, actually %d", 1, intResult.Code))
} }
} }
// test hlen // test hlen
actual := HLen(testDB, toArgs(key)) actual := HLen(testDB, utils2.ToBytesList(key))
if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(len(values)) { if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(len(values)) {
t.Error(fmt.Sprintf("expected %d, actually %d", len(values), intResult.Code)) t.Error(fmt.Sprintf("expected %d, actually %d", len(values), intResult.Code))
} }
@@ -51,24 +52,24 @@ func TestHDel(t *testing.T) {
size := 100 size := 100
// set values // set values
key := RandString(10) key := utils2.RandString(10)
fields := make([]string, size) fields := make([]string, size)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
value := RandString(10) value := utils2.RandString(10)
field := strconv.Itoa(i) field := strconv.Itoa(i)
fields[i] = field fields[i] = field
HSet(testDB, toArgs(key, field, value)) HSet(testDB, utils2.ToBytesList(key, field, value))
} }
// test HDel // test HDel
args := []string{key} args := []string{key}
args = append(args, fields...) args = append(args, fields...)
actual := HDel(testDB, toArgs(args...)) actual := HDel(testDB, utils2.ToBytesList(args...))
if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(len(fields)) { if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(len(fields)) {
t.Error(fmt.Sprintf("expected %d, actually %d", len(fields), intResult.Code)) t.Error(fmt.Sprintf("expected %d, actually %d", len(fields), intResult.Code))
} }
actual = HLen(testDB, toArgs(key)) actual = HLen(testDB, utils2.ToBytesList(key))
if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(0) { if intResult, _ := actual.(*reply.IntReply); intResult.Code != int64(0) {
t.Error(fmt.Sprintf("expected %d, actually %d", 0, intResult.Code)) t.Error(fmt.Sprintf("expected %d, actually %d", 0, intResult.Code))
} }
@@ -79,16 +80,16 @@ func TestHMSet(t *testing.T) {
size := 100 size := 100
// test hset // test hset
key := RandString(10) key := utils2.RandString(10)
fields := make([]string, size) fields := make([]string, size)
values := make([]string, size) values := make([]string, size)
setArgs := []string{key} setArgs := []string{key}
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
fields[i] = RandString(10) fields[i] = utils2.RandString(10)
values[i] = RandString(10) values[i] = utils2.RandString(10)
setArgs = append(setArgs, fields[i], values[i]) setArgs = append(setArgs, fields[i], values[i])
} }
result := HMSet(testDB, toArgs(setArgs...)) result := HMSet(testDB, utils2.ToBytesList(setArgs...))
if _, ok := result.(*reply.OkReply); !ok { if _, ok := result.(*reply.OkReply); !ok {
t.Error(fmt.Sprintf("expected ok, actually %s", string(result.ToBytes()))) t.Error(fmt.Sprintf("expected ok, actually %s", string(result.ToBytes())))
} }
@@ -96,8 +97,8 @@ func TestHMSet(t *testing.T) {
// test HMGet // test HMGet
getArgs := []string{key} getArgs := []string{key}
getArgs = append(getArgs, fields...) getArgs = append(getArgs, fields...)
actual := HMGet(testDB, toArgs(getArgs...)) actual := HMGet(testDB, utils2.ToBytesList(getArgs...))
expected := reply.MakeMultiBulkReply(toArgs(values...)) expected := reply.MakeMultiBulkReply(utils2.ToBytesList(values...))
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(actual.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(actual.ToBytes())))
} }
@@ -106,22 +107,22 @@ func TestHMSet(t *testing.T) {
func TestHGetAll(t *testing.T) { func TestHGetAll(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
size := 100 size := 100
key := RandString(10) key := utils2.RandString(10)
fields := make([]string, size) fields := make([]string, size)
valueSet := make(map[string]bool, size) valueSet := make(map[string]bool, size)
valueMap := make(map[string]string) valueMap := make(map[string]string)
all := make([]string, 0) all := make([]string, 0)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
fields[i] = RandString(10) fields[i] = utils2.RandString(10)
value := RandString(10) value := utils2.RandString(10)
all = append(all, fields[i], value) all = append(all, fields[i], value)
valueMap[fields[i]] = value valueMap[fields[i]] = value
valueSet[value] = true valueSet[value] = true
HSet(testDB, toArgs(key, fields[i], value)) HSet(testDB, utils2.ToBytesList(key, fields[i], value))
} }
// test HGetAll // test HGetAll
result := HGetAll(testDB, toArgs(key)) result := HGetAll(testDB, utils2.ToBytesList(key))
multiBulk, ok := result.(*reply.MultiBulkReply) multiBulk, ok := result.(*reply.MultiBulkReply)
if !ok { if !ok {
t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes()))) t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes())))
@@ -143,7 +144,7 @@ func TestHGetAll(t *testing.T) {
} }
// test HKeys // test HKeys
result = HKeys(testDB, toArgs(key)) result = HKeys(testDB, utils2.ToBytesList(key))
multiBulk, ok = result.(*reply.MultiBulkReply) multiBulk, ok = result.(*reply.MultiBulkReply)
if !ok { if !ok {
t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes()))) t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes())))
@@ -159,7 +160,7 @@ func TestHGetAll(t *testing.T) {
} }
// test HVals // test HVals
result = HVals(testDB, toArgs(key)) result = HVals(testDB, utils2.ToBytesList(key))
multiBulk, ok = result.(*reply.MultiBulkReply) multiBulk, ok = result.(*reply.MultiBulkReply)
if !ok { if !ok {
t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes()))) t.Error(fmt.Sprintf("expected MultiBulkReply, actually %s", string(result.ToBytes())))
@@ -179,21 +180,21 @@ func TestHGetAll(t *testing.T) {
func TestHIncrBy(t *testing.T) { func TestHIncrBy(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils2.RandString(10)
result := HIncrBy(testDB, toArgs(key, "a", "1")) result := HIncrBy(testDB, utils2.ToBytesList(key, "a", "1"))
if bulkResult, _ := result.(*reply.BulkReply); string(bulkResult.Arg) != "1" { if bulkResult, _ := result.(*reply.BulkReply); string(bulkResult.Arg) != "1" {
t.Error(fmt.Sprintf("expected %s, actually %s", "1", string(bulkResult.Arg))) t.Error(fmt.Sprintf("expected %s, actually %s", "1", string(bulkResult.Arg)))
} }
result = HIncrBy(testDB, toArgs(key, "a", "1")) result = HIncrBy(testDB, utils2.ToBytesList(key, "a", "1"))
if bulkResult, _ := result.(*reply.BulkReply); string(bulkResult.Arg) != "2" { if bulkResult, _ := result.(*reply.BulkReply); string(bulkResult.Arg) != "2" {
t.Error(fmt.Sprintf("expected %s, actually %s", "2", string(bulkResult.Arg))) t.Error(fmt.Sprintf("expected %s, actually %s", "2", string(bulkResult.Arg)))
} }
result = HIncrByFloat(testDB, toArgs(key, "b", "1.2")) result = HIncrByFloat(testDB, utils2.ToBytesList(key, "b", "1.2"))
if bulkResult, _ := result.(*reply.BulkReply); string(bulkResult.Arg) != "1.2" { if bulkResult, _ := result.(*reply.BulkReply); string(bulkResult.Arg) != "1.2" {
t.Error(fmt.Sprintf("expected %s, actually %s", "1.2", string(bulkResult.Arg))) t.Error(fmt.Sprintf("expected %s, actually %s", "1.2", string(bulkResult.Arg)))
} }
result = HIncrByFloat(testDB, toArgs(key, "b", "1.2")) result = HIncrByFloat(testDB, utils2.ToBytesList(key, "b", "1.2"))
if bulkResult, _ := result.(*reply.BulkReply); string(bulkResult.Arg) != "2.4" { if bulkResult, _ := result.(*reply.BulkReply); string(bulkResult.Arg) != "2.4" {
t.Error(fmt.Sprintf("expected %s, actually %s", "2.4", string(bulkResult.Arg))) t.Error(fmt.Sprintf("expected %s, actually %s", "2.4", string(bulkResult.Arg)))
} }
@@ -201,15 +202,15 @@ func TestHIncrBy(t *testing.T) {
func TestHSetNX(t *testing.T) { func TestHSetNX(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils2.RandString(10)
field := RandString(10) field := utils2.RandString(10)
value := RandString(10) value := utils2.RandString(10)
result := HSetNX(testDB, toArgs(key, field, value)) result := HSetNX(testDB, utils2.ToBytesList(key, field, value))
asserts.AssertIntReply(t, result, 1) asserts.AssertIntReply(t, result, 1)
value2 := RandString(10) value2 := utils2.RandString(10)
result = HSetNX(testDB, toArgs(key, field, value2)) result = HSetNX(testDB, utils2.ToBytesList(key, field, value2))
asserts.AssertIntReply(t, result, 0) asserts.AssertIntReply(t, result, 0)
result = HGet(testDB, toArgs(key, field)) result = HGet(testDB, utils2.ToBytesList(key, field))
asserts.AssertBulkReply(t, result, value) asserts.AssertBulkReply(t, result, value)
} }

View File

@@ -2,6 +2,7 @@ package db
import ( import (
"fmt" "fmt"
"github.com/hdt3213/godis/lib/utils"
"github.com/hdt3213/godis/redis/reply" "github.com/hdt3213/godis/redis/reply"
"github.com/hdt3213/godis/redis/reply/asserts" "github.com/hdt3213/godis/redis/reply/asserts"
"strconv" "strconv"
@@ -11,64 +12,64 @@ import (
func TestExists(t *testing.T) { func TestExists(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils.RandString(10)
value := RandString(10) value := utils.RandString(10)
Set(testDB, toArgs(key, value)) Set(testDB, utils.ToBytesList(key, value))
result := Exists(testDB, toArgs(key)) result := Exists(testDB, utils.ToBytesList(key))
asserts.AssertIntReply(t, result, 1) asserts.AssertIntReply(t, result, 1)
key = RandString(10) key = utils.RandString(10)
result = Exists(testDB, toArgs(key)) result = Exists(testDB, utils.ToBytesList(key))
asserts.AssertIntReply(t, result, 0) asserts.AssertIntReply(t, result, 0)
} }
func TestType(t *testing.T) { func TestType(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils.RandString(10)
value := RandString(10) value := utils.RandString(10)
Set(testDB, toArgs(key, value)) Set(testDB, utils.ToBytesList(key, value))
result := Type(testDB, toArgs(key)) result := Type(testDB, utils.ToBytesList(key))
asserts.AssertStatusReply(t, result, "string") asserts.AssertStatusReply(t, result, "string")
Del(testDB, toArgs(key)) Del(testDB, utils.ToBytesList(key))
result = Type(testDB, toArgs(key)) result = Type(testDB, utils.ToBytesList(key))
asserts.AssertStatusReply(t, result, "none") asserts.AssertStatusReply(t, result, "none")
RPush(testDB, toArgs(key, value)) RPush(testDB, utils.ToBytesList(key, value))
result = Type(testDB, toArgs(key)) result = Type(testDB, utils.ToBytesList(key))
asserts.AssertStatusReply(t, result, "list") asserts.AssertStatusReply(t, result, "list")
Del(testDB, toArgs(key)) Del(testDB, utils.ToBytesList(key))
HSet(testDB, toArgs(key, key, value)) HSet(testDB, utils.ToBytesList(key, key, value))
result = Type(testDB, toArgs(key)) result = Type(testDB, utils.ToBytesList(key))
asserts.AssertStatusReply(t, result, "hash") asserts.AssertStatusReply(t, result, "hash")
Del(testDB, toArgs(key)) Del(testDB, utils.ToBytesList(key))
SAdd(testDB, toArgs(key, value)) SAdd(testDB, utils.ToBytesList(key, value))
result = Type(testDB, toArgs(key)) result = Type(testDB, utils.ToBytesList(key))
asserts.AssertStatusReply(t, result, "set") asserts.AssertStatusReply(t, result, "set")
Del(testDB, toArgs(key)) Del(testDB, utils.ToBytesList(key))
ZAdd(testDB, toArgs(key, "1", value)) ZAdd(testDB, utils.ToBytesList(key, "1", value))
result = Type(testDB, toArgs(key)) result = Type(testDB, utils.ToBytesList(key))
asserts.AssertStatusReply(t, result, "zset") asserts.AssertStatusReply(t, result, "zset")
} }
func TestRename(t *testing.T) { func TestRename(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils.RandString(10)
value := RandString(10) value := utils.RandString(10)
newKey := key + RandString(2) newKey := key + utils.RandString(2)
Set(testDB, toArgs(key, value, "ex", "1000")) Set(testDB, utils.ToBytesList(key, value, "ex", "1000"))
result := Rename(testDB, toArgs(key, newKey)) result := Rename(testDB, utils.ToBytesList(key, newKey))
if _, ok := result.(*reply.OkReply); !ok { if _, ok := result.(*reply.OkReply); !ok {
t.Error("expect ok") t.Error("expect ok")
return return
} }
result = Exists(testDB, toArgs(key)) result = Exists(testDB, utils.ToBytesList(key))
asserts.AssertIntReply(t, result, 0) asserts.AssertIntReply(t, result, 0)
result = Exists(testDB, toArgs(newKey)) result = Exists(testDB, utils.ToBytesList(newKey))
asserts.AssertIntReply(t, result, 1) asserts.AssertIntReply(t, result, 1)
// check ttl // check ttl
result = TTL(testDB, toArgs(newKey)) result = TTL(testDB, utils.ToBytesList(newKey))
intResult, ok := result.(*reply.IntReply) intResult, ok := result.(*reply.IntReply)
if !ok { if !ok {
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes())) t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
@@ -82,17 +83,17 @@ func TestRename(t *testing.T) {
func TestRenameNx(t *testing.T) { func TestRenameNx(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils.RandString(10)
value := RandString(10) value := utils.RandString(10)
newKey := key + RandString(2) newKey := key + utils.RandString(2)
Set(testDB, toArgs(key, value, "ex", "1000")) Set(testDB, utils.ToBytesList(key, value, "ex", "1000"))
result := RenameNx(testDB, toArgs(key, newKey)) result := RenameNx(testDB, utils.ToBytesList(key, newKey))
asserts.AssertIntReply(t, result, 1) asserts.AssertIntReply(t, result, 1)
result = Exists(testDB, toArgs(key)) result = Exists(testDB, utils.ToBytesList(key))
asserts.AssertIntReply(t, result, 0) asserts.AssertIntReply(t, result, 0)
result = Exists(testDB, toArgs(newKey)) result = Exists(testDB, utils.ToBytesList(newKey))
asserts.AssertIntReply(t, result, 1) asserts.AssertIntReply(t, result, 1)
result = TTL(testDB, toArgs(newKey)) result = TTL(testDB, utils.ToBytesList(newKey))
intResult, ok := result.(*reply.IntReply) intResult, ok := result.(*reply.IntReply)
if !ok { if !ok {
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes())) t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
@@ -106,13 +107,13 @@ func TestRenameNx(t *testing.T) {
func TestTTL(t *testing.T) { func TestTTL(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils.RandString(10)
value := RandString(10) value := utils.RandString(10)
Set(testDB, toArgs(key, value)) Set(testDB, utils.ToBytesList(key, value))
result := Expire(testDB, toArgs(key, "1000")) result := Expire(testDB, utils.ToBytesList(key, "1000"))
asserts.AssertIntReply(t, result, 1) asserts.AssertIntReply(t, result, 1)
result = TTL(testDB, toArgs(key)) result = TTL(testDB, utils.ToBytesList(key))
intResult, ok := result.(*reply.IntReply) intResult, ok := result.(*reply.IntReply)
if !ok { if !ok {
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes())) t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
@@ -123,14 +124,14 @@ func TestTTL(t *testing.T) {
return return
} }
result = Persist(testDB, toArgs(key)) result = Persist(testDB, utils.ToBytesList(key))
asserts.AssertIntReply(t, result, 1) asserts.AssertIntReply(t, result, 1)
result = TTL(testDB, toArgs(key)) result = TTL(testDB, utils.ToBytesList(key))
asserts.AssertIntReply(t, result, -1) asserts.AssertIntReply(t, result, -1)
result = PExpire(testDB, toArgs(key, "1000000")) result = PExpire(testDB, utils.ToBytesList(key, "1000000"))
asserts.AssertIntReply(t, result, 1) asserts.AssertIntReply(t, result, 1)
result = PTTL(testDB, toArgs(key)) result = PTTL(testDB, utils.ToBytesList(key))
intResult, ok = result.(*reply.IntReply) intResult, ok = result.(*reply.IntReply)
if !ok { if !ok {
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes())) t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
@@ -144,14 +145,14 @@ func TestTTL(t *testing.T) {
func TestExpireAt(t *testing.T) { func TestExpireAt(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils.RandString(10)
value := RandString(10) value := utils.RandString(10)
Set(testDB, toArgs(key, value)) Set(testDB, utils.ToBytesList(key, value))
expireAt := time.Now().Add(time.Minute).Unix() expireAt := time.Now().Add(time.Minute).Unix()
result := ExpireAt(testDB, toArgs(key, strconv.FormatInt(expireAt, 10))) result := ExpireAt(testDB, utils.ToBytesList(key, strconv.FormatInt(expireAt, 10)))
asserts.AssertIntReply(t, result, 1) asserts.AssertIntReply(t, result, 1)
result = TTL(testDB, toArgs(key)) result = TTL(testDB, utils.ToBytesList(key))
intResult, ok := result.(*reply.IntReply) intResult, ok := result.(*reply.IntReply)
if !ok { if !ok {
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes())) t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
@@ -163,9 +164,9 @@ func TestExpireAt(t *testing.T) {
} }
expireAt = time.Now().Add(time.Minute).Unix() expireAt = time.Now().Add(time.Minute).Unix()
result = PExpireAt(testDB, toArgs(key, strconv.FormatInt(expireAt*1000, 10))) result = PExpireAt(testDB, utils.ToBytesList(key, strconv.FormatInt(expireAt*1000, 10)))
asserts.AssertIntReply(t, result, 1) asserts.AssertIntReply(t, result, 1)
result = TTL(testDB, toArgs(key)) result = TTL(testDB, utils.ToBytesList(key))
intResult, ok = result.(*reply.IntReply) intResult, ok = result.(*reply.IntReply)
if !ok { if !ok {
t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes())) t.Error(fmt.Sprintf("expected int reply, actually %s", result.ToBytes()))
@@ -179,16 +180,16 @@ func TestExpireAt(t *testing.T) {
func TestKeys(t *testing.T) { func TestKeys(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils.RandString(10)
value := RandString(10) value := utils.RandString(10)
Set(testDB, toArgs(key, value)) Set(testDB, utils.ToBytesList(key, value))
Set(testDB, toArgs("a:"+key, value)) Set(testDB, utils.ToBytesList("a:"+key, value))
Set(testDB, toArgs("b:"+key, value)) Set(testDB, utils.ToBytesList("b:"+key, value))
result := Keys(testDB, toArgs("*")) result := Keys(testDB, utils.ToBytesList("*"))
asserts.AssertMultiBulkReplySize(t, result, 3) asserts.AssertMultiBulkReplySize(t, result, 3)
result = Keys(testDB, toArgs("a:*")) result = Keys(testDB, utils.ToBytesList("a:*"))
asserts.AssertMultiBulkReplySize(t, result, 1) asserts.AssertMultiBulkReplySize(t, result, 1)
result = Keys(testDB, toArgs("?:*")) result = Keys(testDB, utils.ToBytesList("?:*"))
asserts.AssertMultiBulkReplySize(t, result, 2) asserts.AssertMultiBulkReplySize(t, result, 2)
} }

View File

@@ -3,6 +3,7 @@ package db
import ( import (
"fmt" "fmt"
"github.com/hdt3213/godis/datastruct/utils" "github.com/hdt3213/godis/datastruct/utils"
utils2 "github.com/hdt3213/godis/lib/utils"
"github.com/hdt3213/godis/redis/reply" "github.com/hdt3213/godis/redis/reply"
"strconv" "strconv"
"testing" "testing"
@@ -13,67 +14,67 @@ func TestPush(t *testing.T) {
size := 100 size := 100
// rpush single // rpush single
key := RandString(10) key := utils2.RandString(10)
values := make([][]byte, size) values := make([][]byte, size)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
value := RandString(10) value := utils2.RandString(10)
values[i] = []byte(value) values[i] = []byte(value)
result := RPush(testDB, toArgs(key, value)) result := RPush(testDB, utils2.ToBytesList(key, value))
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(i+1) { if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(i+1) {
t.Error(fmt.Sprintf("expected %d, actually %d", i+1, intResult.Code)) t.Error(fmt.Sprintf("expected %d, actually %d", i+1, intResult.Code))
} }
} }
actual := LRange(testDB, toArgs(key, "0", "-1")) actual := LRange(testDB, utils2.ToBytesList(key, "0", "-1"))
expected := reply.MakeMultiBulkReply(values) expected := reply.MakeMultiBulkReply(values)
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error("push error") t.Error("push error")
} }
Del(testDB, toArgs(key)) Del(testDB, utils2.ToBytesList(key))
// rpush multi // rpush multi
key = RandString(10) key = utils2.RandString(10)
values = make([][]byte, size+1) values = make([][]byte, size+1)
values[0] = []byte(key) values[0] = []byte(key)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
value := RandString(10) value := utils2.RandString(10)
values[i+1] = []byte(value) values[i+1] = []byte(value)
} }
result := RPush(testDB, values) result := RPush(testDB, values)
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(size) { if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(size) {
t.Error(fmt.Sprintf("expected %d, actually %d", size, intResult.Code)) t.Error(fmt.Sprintf("expected %d, actually %d", size, intResult.Code))
} }
actual = LRange(testDB, toArgs(key, "0", "-1")) actual = LRange(testDB, utils2.ToBytesList(key, "0", "-1"))
expected = reply.MakeMultiBulkReply(values[1:]) expected = reply.MakeMultiBulkReply(values[1:])
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error("push error") t.Error("push error")
} }
Del(testDB, toArgs(key)) Del(testDB, utils2.ToBytesList(key))
// left push single // left push single
key = RandString(10) key = utils2.RandString(10)
values = make([][]byte, size) values = make([][]byte, size)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
value := RandString(10) value := utils2.RandString(10)
values[size-i-1] = []byte(value) values[size-i-1] = []byte(value)
result = LPush(testDB, toArgs(key, value)) result = LPush(testDB, utils2.ToBytesList(key, value))
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(i+1) { if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(i+1) {
t.Error(fmt.Sprintf("expected %d, actually %d", i+1, intResult.Code)) t.Error(fmt.Sprintf("expected %d, actually %d", i+1, intResult.Code))
} }
} }
actual = LRange(testDB, toArgs(key, "0", "-1")) actual = LRange(testDB, utils2.ToBytesList(key, "0", "-1"))
expected = reply.MakeMultiBulkReply(values) expected = reply.MakeMultiBulkReply(values)
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error("push error") t.Error("push error")
} }
Del(testDB, toArgs(key)) Del(testDB, utils2.ToBytesList(key))
// left push multi // left push multi
key = RandString(10) key = utils2.RandString(10)
values = make([][]byte, size+1) values = make([][]byte, size+1)
values[0] = []byte(key) values[0] = []byte(key)
expectedValues := make([][]byte, size) expectedValues := make([][]byte, size)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
value := RandString(10) value := utils2.RandString(10)
values[i+1] = []byte(value) values[i+1] = []byte(value)
expectedValues[size-i-1] = []byte(value) expectedValues[size-i-1] = []byte(value)
} }
@@ -81,29 +82,29 @@ func TestPush(t *testing.T) {
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(size) { if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(size) {
t.Error(fmt.Sprintf("expected %d, actually %d", size, intResult.Code)) t.Error(fmt.Sprintf("expected %d, actually %d", size, intResult.Code))
} }
actual = LRange(testDB, toArgs(key, "0", "-1")) actual = LRange(testDB, utils2.ToBytesList(key, "0", "-1"))
expected = reply.MakeMultiBulkReply(expectedValues) expected = reply.MakeMultiBulkReply(expectedValues)
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error("push error") t.Error("push error")
} }
Del(testDB, toArgs(key)) Del(testDB, utils2.ToBytesList(key))
} }
func TestLRange(t *testing.T) { func TestLRange(t *testing.T) {
// prepare list // prepare list
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
size := 100 size := 100
key := RandString(10) key := utils2.RandString(10)
values := make([][]byte, size) values := make([][]byte, size)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
value := RandString(10) value := utils2.RandString(10)
RPush(testDB, toArgs(key, value)) RPush(testDB, utils2.ToBytesList(key, value))
values[i] = []byte(value) values[i] = []byte(value)
} }
start := "0" start := "0"
end := "9" end := "9"
actual := LRange(testDB, toArgs(key, start, end)) actual := LRange(testDB, utils2.ToBytesList(key, start, end))
expected := reply.MakeMultiBulkReply(values[0:10]) expected := reply.MakeMultiBulkReply(values[0:10])
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("range error [%s, %s]", start, end)) t.Error(fmt.Sprintf("range error [%s, %s]", start, end))
@@ -111,7 +112,7 @@ func TestLRange(t *testing.T) {
start = "0" start = "0"
end = "200" end = "200"
actual = LRange(testDB, toArgs(key, start, end)) actual = LRange(testDB, utils2.ToBytesList(key, start, end))
expected = reply.MakeMultiBulkReply(values) expected = reply.MakeMultiBulkReply(values)
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("range error [%s, %s]", start, end)) t.Error(fmt.Sprintf("range error [%s, %s]", start, end))
@@ -119,7 +120,7 @@ func TestLRange(t *testing.T) {
start = "0" start = "0"
end = "-10" end = "-10"
actual = LRange(testDB, toArgs(key, start, end)) actual = LRange(testDB, utils2.ToBytesList(key, start, end))
expected = reply.MakeMultiBulkReply(values[0 : size-10+1]) expected = reply.MakeMultiBulkReply(values[0 : size-10+1])
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("range error [%s, %s]", start, end)) t.Error(fmt.Sprintf("range error [%s, %s]", start, end))
@@ -127,7 +128,7 @@ func TestLRange(t *testing.T) {
start = "0" start = "0"
end = "-200" end = "-200"
actual = LRange(testDB, toArgs(key, start, end)) actual = LRange(testDB, utils2.ToBytesList(key, start, end))
expected = reply.MakeMultiBulkReply(values[0:0]) expected = reply.MakeMultiBulkReply(values[0:0])
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("range error [%s, %s]", start, end)) t.Error(fmt.Sprintf("range error [%s, %s]", start, end))
@@ -135,7 +136,7 @@ func TestLRange(t *testing.T) {
start = "-10" start = "-10"
end = "-1" end = "-1"
actual = LRange(testDB, toArgs(key, start, end)) actual = LRange(testDB, utils2.ToBytesList(key, start, end))
expected = reply.MakeMultiBulkReply(values[90:]) expected = reply.MakeMultiBulkReply(values[90:])
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("range error [%s, %s]", start, end)) t.Error(fmt.Sprintf("range error [%s, %s]", start, end))
@@ -146,21 +147,21 @@ func TestLIndex(t *testing.T) {
// prepare list // prepare list
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
size := 100 size := 100
key := RandString(10) key := utils2.RandString(10)
values := make([][]byte, size) values := make([][]byte, size)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
value := RandString(10) value := utils2.RandString(10)
RPush(testDB, toArgs(key, value)) RPush(testDB, utils2.ToBytesList(key, value))
values[i] = []byte(value) values[i] = []byte(value)
} }
result := LLen(testDB, toArgs(key)) result := LLen(testDB, utils2.ToBytesList(key))
if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(size) { if intResult, _ := result.(*reply.IntReply); intResult.Code != int64(size) {
t.Error(fmt.Sprintf("expected %d, actually %d", size, intResult.Code)) t.Error(fmt.Sprintf("expected %d, actually %d", size, intResult.Code))
} }
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
result = LIndex(testDB, toArgs(key, strconv.Itoa(i))) result = LIndex(testDB, utils2.ToBytesList(key, strconv.Itoa(i)))
expected := reply.MakeBulkReply(values[i]) expected := reply.MakeBulkReply(values[i])
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
@@ -168,7 +169,7 @@ func TestLIndex(t *testing.T) {
} }
for i := 1; i <= size; i++ { for i := 1; i <= size; i++ {
result = LIndex(testDB, toArgs(key, strconv.Itoa(-i))) result = LIndex(testDB, utils2.ToBytesList(key, strconv.Itoa(-i)))
expected := reply.MakeBulkReply(values[size-i]) expected := reply.MakeBulkReply(values[size-i])
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
@@ -179,33 +180,33 @@ func TestLIndex(t *testing.T) {
func TestLRem(t *testing.T) { func TestLRem(t *testing.T) {
// prepare list // prepare list
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils2.RandString(10)
values := []string{key, "a", "b", "a", "a", "c", "a", "a"} values := []string{key, "a", "b", "a", "a", "c", "a", "a"}
RPush(testDB, toArgs(values...)) RPush(testDB, utils2.ToBytesList(values...))
result := LRem(testDB, toArgs(key, "1", "a")) result := LRem(testDB, utils2.ToBytesList(key, "1", "a"))
if intResult, _ := result.(*reply.IntReply); intResult.Code != 1 { if intResult, _ := result.(*reply.IntReply); intResult.Code != 1 {
t.Error(fmt.Sprintf("expected %d, actually %d", 1, intResult.Code)) t.Error(fmt.Sprintf("expected %d, actually %d", 1, intResult.Code))
} }
result = LLen(testDB, toArgs(key)) result = LLen(testDB, utils2.ToBytesList(key))
if intResult, _ := result.(*reply.IntReply); intResult.Code != 6 { if intResult, _ := result.(*reply.IntReply); intResult.Code != 6 {
t.Error(fmt.Sprintf("expected %d, actually %d", 6, intResult.Code)) t.Error(fmt.Sprintf("expected %d, actually %d", 6, intResult.Code))
} }
result = LRem(testDB, toArgs(key, "-2", "a")) result = LRem(testDB, utils2.ToBytesList(key, "-2", "a"))
if intResult, _ := result.(*reply.IntReply); intResult.Code != 2 { if intResult, _ := result.(*reply.IntReply); intResult.Code != 2 {
t.Error(fmt.Sprintf("expected %d, actually %d", 2, intResult.Code)) t.Error(fmt.Sprintf("expected %d, actually %d", 2, intResult.Code))
} }
result = LLen(testDB, toArgs(key)) result = LLen(testDB, utils2.ToBytesList(key))
if intResult, _ := result.(*reply.IntReply); intResult.Code != 4 { if intResult, _ := result.(*reply.IntReply); intResult.Code != 4 {
t.Error(fmt.Sprintf("expected %d, actually %d", 4, intResult.Code)) t.Error(fmt.Sprintf("expected %d, actually %d", 4, intResult.Code))
} }
result = LRem(testDB, toArgs(key, "0", "a")) result = LRem(testDB, utils2.ToBytesList(key, "0", "a"))
if intResult, _ := result.(*reply.IntReply); intResult.Code != 2 { if intResult, _ := result.(*reply.IntReply); intResult.Code != 2 {
t.Error(fmt.Sprintf("expected %d, actually %d", 2, intResult.Code)) t.Error(fmt.Sprintf("expected %d, actually %d", 2, intResult.Code))
} }
result = LLen(testDB, toArgs(key)) result = LLen(testDB, utils2.ToBytesList(key))
if intResult, _ := result.(*reply.IntReply); intResult.Code != 2 { if intResult, _ := result.(*reply.IntReply); intResult.Code != 2 {
t.Error(fmt.Sprintf("expected %d, actually %d", 2, intResult.Code)) t.Error(fmt.Sprintf("expected %d, actually %d", 2, intResult.Code))
} }
@@ -213,20 +214,20 @@ func TestLRem(t *testing.T) {
func TestLSet(t *testing.T) { func TestLSet(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils2.RandString(10)
values := []string{key, "a", "b", "c", "d", "e", "f"} values := []string{key, "a", "b", "c", "d", "e", "f"}
RPush(testDB, toArgs(values...)) RPush(testDB, utils2.ToBytesList(values...))
// test positive index // test positive index
size := len(values) - 1 size := len(values) - 1
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
indexStr := strconv.Itoa(i) indexStr := strconv.Itoa(i)
value := RandString(10) value := utils2.RandString(10)
result := LSet(testDB, toArgs(key, indexStr, value)) result := LSet(testDB, utils2.ToBytesList(key, indexStr, value))
if _, ok := result.(*reply.OkReply); !ok { if _, ok := result.(*reply.OkReply); !ok {
t.Error(fmt.Sprintf("expected OK, actually %s", string(result.ToBytes()))) t.Error(fmt.Sprintf("expected OK, actually %s", string(result.ToBytes())))
} }
result = LIndex(testDB, toArgs(key, indexStr)) result = LIndex(testDB, utils2.ToBytesList(key, indexStr))
expected := reply.MakeBulkReply([]byte(value)) expected := reply.MakeBulkReply([]byte(value))
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
@@ -234,12 +235,12 @@ func TestLSet(t *testing.T) {
} }
// test negative index // test negative index
for i := 1; i <= size; i++ { for i := 1; i <= size; i++ {
value := RandString(10) value := utils2.RandString(10)
result := LSet(testDB, toArgs(key, strconv.Itoa(-i), value)) result := LSet(testDB, utils2.ToBytesList(key, strconv.Itoa(-i), value))
if _, ok := result.(*reply.OkReply); !ok { if _, ok := result.(*reply.OkReply); !ok {
t.Error(fmt.Sprintf("expected OK, actually %s", string(result.ToBytes()))) t.Error(fmt.Sprintf("expected OK, actually %s", string(result.ToBytes())))
} }
result = LIndex(testDB, toArgs(key, strconv.Itoa(len(values)-i-1))) result = LIndex(testDB, utils2.ToBytesList(key, strconv.Itoa(len(values)-i-1)))
expected := reply.MakeBulkReply([]byte(value)) expected := reply.MakeBulkReply([]byte(value))
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
@@ -247,17 +248,17 @@ func TestLSet(t *testing.T) {
} }
// test illegal index // test illegal index
value := RandString(10) value := utils2.RandString(10)
result := LSet(testDB, toArgs(key, strconv.Itoa(-len(values)-1), value)) result := LSet(testDB, utils2.ToBytesList(key, strconv.Itoa(-len(values)-1), value))
expected := reply.MakeErrReply("ERR index out of range") expected := reply.MakeErrReply("ERR index out of range")
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
} }
result = LSet(testDB, toArgs(key, strconv.Itoa(len(values)), value)) result = LSet(testDB, utils2.ToBytesList(key, strconv.Itoa(len(values)), value))
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
} }
result = LSet(testDB, toArgs(key, "a", value)) result = LSet(testDB, utils2.ToBytesList(key, "a", value))
expected = reply.MakeErrReply("ERR value is not an integer or out of range") expected = reply.MakeErrReply("ERR value is not an integer or out of range")
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
@@ -266,19 +267,19 @@ func TestLSet(t *testing.T) {
func TestLPop(t *testing.T) { func TestLPop(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils2.RandString(10)
values := []string{key, "a", "b", "c", "d", "e", "f"} values := []string{key, "a", "b", "c", "d", "e", "f"}
RPush(testDB, toArgs(values...)) RPush(testDB, utils2.ToBytesList(values...))
size := len(values) - 1 size := len(values) - 1
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
result := LPop(testDB, toArgs(key)) result := LPop(testDB, utils2.ToBytesList(key))
expected := reply.MakeBulkReply([]byte(values[i+1])) expected := reply.MakeBulkReply([]byte(values[i+1]))
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
} }
} }
result := RPop(testDB, toArgs(key)) result := RPop(testDB, utils2.ToBytesList(key))
expected := &reply.NullBulkReply{} expected := &reply.NullBulkReply{}
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
@@ -287,19 +288,19 @@ func TestLPop(t *testing.T) {
func TestRPop(t *testing.T) { func TestRPop(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils2.RandString(10)
values := []string{key, "a", "b", "c", "d", "e", "f"} values := []string{key, "a", "b", "c", "d", "e", "f"}
RPush(testDB, toArgs(values...)) RPush(testDB, utils2.ToBytesList(values...))
size := len(values) - 1 size := len(values) - 1
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
result := RPop(testDB, toArgs(key)) result := RPop(testDB, utils2.ToBytesList(key))
expected := reply.MakeBulkReply([]byte(values[len(values)-i-1])) expected := reply.MakeBulkReply([]byte(values[len(values)-i-1]))
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
} }
} }
result := RPop(testDB, toArgs(key)) result := RPop(testDB, utils2.ToBytesList(key))
expected := &reply.NullBulkReply{} expected := &reply.NullBulkReply{}
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
@@ -308,24 +309,24 @@ func TestRPop(t *testing.T) {
func TestRPopLPush(t *testing.T) { func TestRPopLPush(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key1 := RandString(10) key1 := utils2.RandString(10)
key2 := RandString(10) key2 := utils2.RandString(10)
values := []string{key1, "a", "b", "c", "d", "e", "f"} values := []string{key1, "a", "b", "c", "d", "e", "f"}
RPush(testDB, toArgs(values...)) RPush(testDB, utils2.ToBytesList(values...))
size := len(values) - 1 size := len(values) - 1
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
result := RPopLPush(testDB, toArgs(key1, key2)) result := RPopLPush(testDB, utils2.ToBytesList(key1, key2))
expected := reply.MakeBulkReply([]byte(values[len(values)-i-1])) expected := reply.MakeBulkReply([]byte(values[len(values)-i-1]))
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
} }
result = LIndex(testDB, toArgs(key2, "0")) result = LIndex(testDB, utils2.ToBytesList(key2, "0"))
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
} }
} }
result := RPop(testDB, toArgs(key1)) result := RPop(testDB, utils2.ToBytesList(key1))
expected := &reply.NullBulkReply{} expected := &reply.NullBulkReply{}
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
@@ -334,22 +335,22 @@ func TestRPopLPush(t *testing.T) {
func TestRPushX(t *testing.T) { func TestRPushX(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils2.RandString(10)
result := RPushX(testDB, toArgs(key, "1")) result := RPushX(testDB, utils2.ToBytesList(key, "1"))
expected := reply.MakeIntReply(int64(0)) expected := reply.MakeIntReply(int64(0))
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
} }
RPush(testDB, toArgs(key, "1")) RPush(testDB, utils2.ToBytesList(key, "1"))
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
value := RandString(10) value := utils2.RandString(10)
result := RPushX(testDB, toArgs(key, value)) result := RPushX(testDB, utils2.ToBytesList(key, value))
expected := reply.MakeIntReply(int64(i + 2)) expected := reply.MakeIntReply(int64(i + 2))
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
} }
result = LIndex(testDB, toArgs(key, "-1")) result = LIndex(testDB, utils2.ToBytesList(key, "-1"))
expected2 := reply.MakeBulkReply([]byte(value)) expected2 := reply.MakeBulkReply([]byte(value))
if !utils.BytesEquals(result.ToBytes(), expected2.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected2.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected2.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected2.ToBytes()), string(result.ToBytes())))
@@ -359,22 +360,22 @@ func TestRPushX(t *testing.T) {
func TestLPushX(t *testing.T) { func TestLPushX(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils2.RandString(10)
result := RPushX(testDB, toArgs(key, "1")) result := RPushX(testDB, utils2.ToBytesList(key, "1"))
expected := reply.MakeIntReply(int64(0)) expected := reply.MakeIntReply(int64(0))
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
} }
LPush(testDB, toArgs(key, "1")) LPush(testDB, utils2.ToBytesList(key, "1"))
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
value := RandString(10) value := utils2.RandString(10)
result := LPushX(testDB, toArgs(key, value)) result := LPushX(testDB, utils2.ToBytesList(key, value))
expected := reply.MakeIntReply(int64(i + 2)) expected := reply.MakeIntReply(int64(i + 2))
if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected.ToBytes()), string(result.ToBytes())))
} }
result = LIndex(testDB, toArgs(key, "0")) result = LIndex(testDB, utils2.ToBytesList(key, "0"))
expected2 := reply.MakeBulkReply([]byte(value)) expected2 := reply.MakeBulkReply([]byte(value))
if !utils.BytesEquals(result.ToBytes(), expected2.ToBytes()) { if !utils.BytesEquals(result.ToBytes(), expected2.ToBytes()) {
t.Error(fmt.Sprintf("expected %s, actually %s", string(expected2.ToBytes()), string(result.ToBytes()))) t.Error(fmt.Sprintf("expected %s, actually %s", string(expected2.ToBytes()), string(result.ToBytes())))

View File

@@ -1,16 +1,17 @@
package db package db
import ( import (
"github.com/hdt3213/godis/lib/utils"
"github.com/hdt3213/godis/redis/reply/asserts" "github.com/hdt3213/godis/redis/reply/asserts"
"testing" "testing"
) )
func TestPing(t *testing.T) { func TestPing(t *testing.T) {
actual := Ping(testDB, toArgs()) actual := Ping(testDB, utils.ToBytesList())
asserts.AssertStatusReply(t, actual, "PONG") asserts.AssertStatusReply(t, actual, "PONG")
val := RandString(5) val := utils.RandString(5)
actual = Ping(testDB, toArgs(val)) actual = Ping(testDB, utils.ToBytesList(val))
asserts.AssertStatusReply(t, actual, val) asserts.AssertStatusReply(t, actual, val)
actual = Ping(testDB, toArgs(val, val)) actual = Ping(testDB, utils.ToBytesList(val, val))
asserts.AssertErrReply(t, actual, "ERR wrong number of arguments for 'ping' command") asserts.AssertErrReply(t, actual, "ERR wrong number of arguments for 'ping' command")
} }

View File

@@ -236,7 +236,7 @@ func SInterStore(db *DB, args [][]byte) redis.Reply {
} }
if set == nil { if set == nil {
db.Remove(dest) // clean ttl and old value db.Remove(dest) // clean ttl and old value
return &reply.EmptyMultiBulkReply{} return reply.MakeIntReply(0)
} }
if result == nil { if result == nil {
@@ -437,7 +437,7 @@ func SDiffStore(db *DB, args [][]byte) redis.Reply {
if i == 0 { if i == 0 {
// early termination // early termination
db.Remove(dest) db.Remove(dest)
return &reply.EmptyMultiBulkReply{} return reply.MakeIntReply(0)
} }
continue continue
} }
@@ -449,7 +449,7 @@ func SDiffStore(db *DB, args [][]byte) redis.Reply {
if result.Len() == 0 { if result.Len() == 0 {
// early termination // early termination
db.Remove(dest) db.Remove(dest)
return &reply.EmptyMultiBulkReply{} return reply.MakeIntReply(0)
} }
} }
} }

View File

@@ -2,6 +2,7 @@ package db
import ( import (
"fmt" "fmt"
"github.com/hdt3213/godis/lib/utils"
"github.com/hdt3213/godis/redis/reply" "github.com/hdt3213/godis/redis/reply"
"github.com/hdt3213/godis/redis/reply/asserts" "github.com/hdt3213/godis/redis/reply/asserts"
"strconv" "strconv"
@@ -14,25 +15,25 @@ func TestSAdd(t *testing.T) {
size := 100 size := 100
// test sadd // test sadd
key := RandString(10) key := utils.RandString(10)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
member := strconv.Itoa(i) member := strconv.Itoa(i)
result := SAdd(testDB, toArgs(key, member)) result := SAdd(testDB, utils.ToBytesList(key, member))
asserts.AssertIntReply(t, result, 1) asserts.AssertIntReply(t, result, 1)
} }
// test scard // test scard
result := SCard(testDB, toArgs(key)) result := SCard(testDB, utils.ToBytesList(key))
asserts.AssertIntReply(t, result, size) asserts.AssertIntReply(t, result, size)
// test is member // test is member
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
member := strconv.Itoa(i) member := strconv.Itoa(i)
result := SIsMember(testDB, toArgs(key, member)) result := SIsMember(testDB, utils.ToBytesList(key, member))
asserts.AssertIntReply(t, result, 1) asserts.AssertIntReply(t, result, 1)
} }
// test members // test members
result = SMembers(testDB, toArgs(key)) result = SMembers(testDB, utils.ToBytesList(key))
multiBulk, ok := result.(*reply.MultiBulkReply) multiBulk, ok := result.(*reply.MultiBulkReply)
if !ok { if !ok {
t.Error(fmt.Sprintf("expected bulk reply, actually %s", result.ToBytes())) t.Error(fmt.Sprintf("expected bulk reply, actually %s", result.ToBytes()))
@@ -49,15 +50,15 @@ func TestSRem(t *testing.T) {
size := 100 size := 100
// mock data // mock data
key := RandString(10) key := utils.RandString(10)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
member := strconv.Itoa(i) member := strconv.Itoa(i)
SAdd(testDB, toArgs(key, member)) SAdd(testDB, utils.ToBytesList(key, member))
} }
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
member := strconv.Itoa(i) member := strconv.Itoa(i)
SRem(testDB, toArgs(key, member)) SRem(testDB, utils.ToBytesList(key, member))
result := SIsMember(testDB, toArgs(key, member)) result := SIsMember(testDB, utils.ToBytesList(key, member))
asserts.AssertIntReply(t, result, 0) asserts.AssertIntReply(t, result, 0)
} }
} }
@@ -70,22 +71,39 @@ func TestSInter(t *testing.T) {
keys := make([]string, 0) keys := make([]string, 0)
start := 0 start := 0
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
key := RandString(10) key := utils.RandString(10)
keys = append(keys, key) keys = append(keys, key)
for j := start; j < size+start; j++ { for j := start; j < size+start; j++ {
member := strconv.Itoa(j) member := strconv.Itoa(j)
SAdd(testDB, toArgs(key, member)) SAdd(testDB, utils.ToBytesList(key, member))
} }
start += step start += step
} }
result := SInter(testDB, toArgs(keys...)) result := SInter(testDB, utils.ToBytesList(keys...))
asserts.AssertMultiBulkReplySize(t, result, 70) asserts.AssertMultiBulkReplySize(t, result, 70)
destKey := RandString(10) destKey := utils.RandString(10)
keysWithDest := []string{destKey} keysWithDest := []string{destKey}
keysWithDest = append(keysWithDest, keys...) keysWithDest = append(keysWithDest, keys...)
result = SInterStore(testDB, toArgs(keysWithDest...)) result = SInterStore(testDB, utils.ToBytesList(keysWithDest...))
asserts.AssertIntReply(t, result, 70) asserts.AssertIntReply(t, result, 70)
// test empty set
FlushAll(testDB, [][]byte{})
key0 := utils.RandString(10)
Del(testDB, utils.ToBytesList(key0))
key1 := utils.RandString(10)
SAdd(testDB, utils.ToBytesList(key1, "a", "b"))
key2 := utils.RandString(10)
SAdd(testDB, utils.ToBytesList(key2, "1", "2"))
result = SInter(testDB, utils.ToBytesList(key0, key1, key2))
asserts.AssertMultiBulkReplySize(t, result, 0)
result = SInter(testDB, utils.ToBytesList(key1, key2))
asserts.AssertMultiBulkReplySize(t, result, 0)
result = SInterStore(testDB, utils.ToBytesList(utils.RandString(10), key0, key1, key2))
asserts.AssertIntReply(t, result, 0)
result = SInterStore(testDB, utils.ToBytesList(utils.RandString(10), key1, key2))
asserts.AssertIntReply(t, result, 0)
} }
func TestSUnion(t *testing.T) { func TestSUnion(t *testing.T) {
@@ -96,21 +114,21 @@ func TestSUnion(t *testing.T) {
keys := make([]string, 0) keys := make([]string, 0)
start := 0 start := 0
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
key := RandString(10) key := utils.RandString(10)
keys = append(keys, key) keys = append(keys, key)
for j := start; j < size+start; j++ { for j := start; j < size+start; j++ {
member := strconv.Itoa(j) member := strconv.Itoa(j)
SAdd(testDB, toArgs(key, member)) SAdd(testDB, utils.ToBytesList(key, member))
} }
start += step start += step
} }
result := SUnion(testDB, toArgs(keys...)) result := SUnion(testDB, utils.ToBytesList(keys...))
asserts.AssertMultiBulkReplySize(t, result, 130) asserts.AssertMultiBulkReplySize(t, result, 130)
destKey := RandString(10) destKey := utils.RandString(10)
keysWithDest := []string{destKey} keysWithDest := []string{destKey}
keysWithDest = append(keysWithDest, keys...) keysWithDest = append(keysWithDest, keys...)
result = SUnionStore(testDB, toArgs(keysWithDest...)) result = SUnionStore(testDB, utils.ToBytesList(keysWithDest...))
asserts.AssertIntReply(t, result, 130) asserts.AssertIntReply(t, result, 130)
} }
@@ -122,39 +140,56 @@ func TestSDiff(t *testing.T) {
keys := make([]string, 0) keys := make([]string, 0)
start := 0 start := 0
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
key := RandString(10) key := utils.RandString(10)
keys = append(keys, key) keys = append(keys, key)
for j := start; j < size+start; j++ { for j := start; j < size+start; j++ {
member := strconv.Itoa(j) member := strconv.Itoa(j)
SAdd(testDB, toArgs(key, member)) SAdd(testDB, utils.ToBytesList(key, member))
} }
start += step start += step
} }
result := SDiff(testDB, toArgs(keys...)) result := SDiff(testDB, utils.ToBytesList(keys...))
asserts.AssertMultiBulkReplySize(t, result, step) asserts.AssertMultiBulkReplySize(t, result, step)
destKey := RandString(10) destKey := utils.RandString(10)
keysWithDest := []string{destKey} keysWithDest := []string{destKey}
keysWithDest = append(keysWithDest, keys...) keysWithDest = append(keysWithDest, keys...)
result = SDiffStore(testDB, toArgs(keysWithDest...)) result = SDiffStore(testDB, utils.ToBytesList(keysWithDest...))
asserts.AssertIntReply(t, result, step) asserts.AssertIntReply(t, result, step)
// test empty set
FlushAll(testDB, [][]byte{})
key0 := utils.RandString(10)
Del(testDB, utils.ToBytesList(key0))
key1 := utils.RandString(10)
SAdd(testDB, utils.ToBytesList(key1, "a", "b"))
key2 := utils.RandString(10)
SAdd(testDB, utils.ToBytesList(key2, "a", "b"))
result = SDiff(testDB, utils.ToBytesList(key0, key1, key2))
asserts.AssertMultiBulkReplySize(t, result, 0)
result = SDiff(testDB, utils.ToBytesList(key1, key2))
asserts.AssertMultiBulkReplySize(t, result, 0)
result = SDiffStore(testDB, utils.ToBytesList(utils.RandString(10), key0, key1, key2))
asserts.AssertIntReply(t, result, 0)
result = SDiffStore(testDB, utils.ToBytesList(utils.RandString(10), key1, key2))
asserts.AssertIntReply(t, result, 0)
} }
func TestSRandMember(t *testing.T) { func TestSRandMember(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils.RandString(10)
for j := 0; j < 100; j++ { for j := 0; j < 100; j++ {
member := strconv.Itoa(j) member := strconv.Itoa(j)
SAdd(testDB, toArgs(key, member)) SAdd(testDB, utils.ToBytesList(key, member))
} }
result := SRandMember(testDB, toArgs(key)) result := SRandMember(testDB, utils.ToBytesList(key))
br, ok := result.(*reply.BulkReply) br, ok := result.(*reply.BulkReply)
if !ok && len(br.Arg) > 0 { if !ok && len(br.Arg) > 0 {
t.Error(fmt.Sprintf("expected bulk reply, actually %s", result.ToBytes())) t.Error(fmt.Sprintf("expected bulk reply, actually %s", result.ToBytes()))
return return
} }
result = SRandMember(testDB, toArgs(key, "10")) result = SRandMember(testDB, utils.ToBytesList(key, "10"))
asserts.AssertMultiBulkReplySize(t, result, 10) asserts.AssertMultiBulkReplySize(t, result, 10)
multiBulk, ok := result.(*reply.MultiBulkReply) multiBulk, ok := result.(*reply.MultiBulkReply)
if !ok { if !ok {
@@ -170,12 +205,12 @@ func TestSRandMember(t *testing.T) {
return return
} }
result = SRandMember(testDB, toArgs(key, "110")) result = SRandMember(testDB, utils.ToBytesList(key, "110"))
asserts.AssertMultiBulkReplySize(t, result, 100) asserts.AssertMultiBulkReplySize(t, result, 100)
result = SRandMember(testDB, toArgs(key, "-10")) result = SRandMember(testDB, utils.ToBytesList(key, "-10"))
asserts.AssertMultiBulkReplySize(t, result, 10) asserts.AssertMultiBulkReplySize(t, result, 10)
result = SRandMember(testDB, toArgs(key, "-110")) result = SRandMember(testDB, utils.ToBytesList(key, "-110"))
asserts.AssertMultiBulkReplySize(t, result, 110) asserts.AssertMultiBulkReplySize(t, result, 110)
} }

View File

@@ -1,6 +1,7 @@
package db package db
import ( import (
"github.com/hdt3213/godis/lib/utils"
"github.com/hdt3213/godis/redis/reply/asserts" "github.com/hdt3213/godis/redis/reply/asserts"
"math/rand" "math/rand"
"strconv" "strconv"
@@ -12,27 +13,27 @@ func TestZAdd(t *testing.T) {
size := 100 size := 100
// add new members // add new members
key := RandString(10) key := utils.RandString(10)
members := make([]string, size) members := make([]string, size)
scores := make([]float64, size) scores := make([]float64, size)
setArgs := []string{key} setArgs := []string{key}
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
members[i] = RandString(10) members[i] = utils.RandString(10)
scores[i] = rand.Float64() scores[i] = rand.Float64()
setArgs = append(setArgs, strconv.FormatFloat(scores[i], 'f', -1, 64), members[i]) setArgs = append(setArgs, strconv.FormatFloat(scores[i], 'f', -1, 64), members[i])
} }
result := ZAdd(testDB, toArgs(setArgs...)) result := ZAdd(testDB, utils.ToBytesList(setArgs...))
asserts.AssertIntReply(t, result, size) asserts.AssertIntReply(t, result, size)
// test zscore and zrank // test zscore and zrank
for i, member := range members { for i, member := range members {
result := ZScore(testDB, toArgs(key, member)) result := ZScore(testDB, utils.ToBytesList(key, member))
score := strconv.FormatFloat(scores[i], 'f', -1, 64) score := strconv.FormatFloat(scores[i], 'f', -1, 64)
asserts.AssertBulkReply(t, result, score) asserts.AssertBulkReply(t, result, score)
} }
// test zcard // test zcard
result = ZCard(testDB, toArgs(key)) result = ZCard(testDB, utils.ToBytesList(key))
asserts.AssertIntReply(t, result, size) asserts.AssertIntReply(t, result, size)
// update members // update members
@@ -41,12 +42,12 @@ func TestZAdd(t *testing.T) {
scores[i] = rand.Float64() + 100 scores[i] = rand.Float64() + 100
setArgs = append(setArgs, strconv.FormatFloat(scores[i], 'f', -1, 64), members[i]) setArgs = append(setArgs, strconv.FormatFloat(scores[i], 'f', -1, 64), members[i])
} }
result = ZAdd(testDB, toArgs(setArgs...)) result = ZAdd(testDB, utils.ToBytesList(setArgs...))
asserts.AssertIntReply(t, result, 0) // return number of new members asserts.AssertIntReply(t, result, 0) // return number of new members
// test updated score // test updated score
for i, member := range members { for i, member := range members {
result := ZScore(testDB, toArgs(key, member)) result := ZScore(testDB, utils.ToBytesList(key, member))
score := strconv.FormatFloat(scores[i], 'f', -1, 64) score := strconv.FormatFloat(scores[i], 'f', -1, 64)
asserts.AssertBulkReply(t, result, score) asserts.AssertBulkReply(t, result, score)
} }
@@ -55,23 +56,23 @@ func TestZAdd(t *testing.T) {
func TestZRank(t *testing.T) { func TestZRank(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
size := 100 size := 100
key := RandString(10) key := utils.RandString(10)
members := make([]string, size) members := make([]string, size)
scores := make([]int, size) scores := make([]int, size)
setArgs := []string{key} setArgs := []string{key}
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
members[i] = RandString(10) members[i] = utils.RandString(10)
scores[i] = i scores[i] = i
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i]) setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
} }
ZAdd(testDB, toArgs(setArgs...)) ZAdd(testDB, utils.ToBytesList(setArgs...))
// test zrank // test zrank
for i, member := range members { for i, member := range members {
result := ZRank(testDB, toArgs(key, member)) result := ZRank(testDB, utils.ToBytesList(key, member))
asserts.AssertIntReply(t, result, i) asserts.AssertIntReply(t, result, i)
result = ZRevRank(testDB, toArgs(key, member)) result = ZRevRank(testDB, utils.ToBytesList(key, member))
asserts.AssertIntReply(t, result, size-i-1) asserts.AssertIntReply(t, result, size-i-1)
} }
} }
@@ -80,16 +81,16 @@ func TestZRange(t *testing.T) {
// prepare // prepare
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
size := 100 size := 100
key := RandString(10) key := utils.RandString(10)
members := make([]string, size) members := make([]string, size)
scores := make([]int, size) scores := make([]int, size)
setArgs := []string{key} setArgs := []string{key}
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
members[i] = RandString(10) members[i] = utils.RandString(10)
scores[i] = i scores[i] = i
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i]) setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
} }
ZAdd(testDB, toArgs(setArgs...)) ZAdd(testDB, utils.ToBytesList(setArgs...))
reverseMembers := make([]string, size) reverseMembers := make([]string, size)
for i, v := range members { for i, v := range members {
reverseMembers[size-i-1] = v reverseMembers[size-i-1] = v
@@ -97,37 +98,39 @@ func TestZRange(t *testing.T) {
start := "0" start := "0"
end := "9" end := "9"
result := ZRange(testDB, toArgs(key, start, end)) result := ZRange(testDB, utils.ToBytesList(key, start, end))
asserts.AssertMultiBulkReply(t, result, members[0:10]) asserts.AssertMultiBulkReply(t, result, members[0:10])
result = ZRevRange(testDB, toArgs(key, start, end)) result = ZRange(testDB, utils.ToBytesList(key, start, end, "WITHSCORES"))
asserts.AssertMultiBulkReplySize(t, result, 20)
result = ZRevRange(testDB, utils.ToBytesList(key, start, end))
asserts.AssertMultiBulkReply(t, result, reverseMembers[0:10]) asserts.AssertMultiBulkReply(t, result, reverseMembers[0:10])
start = "0" start = "0"
end = "200" end = "200"
result = ZRange(testDB, toArgs(key, start, end)) result = ZRange(testDB, utils.ToBytesList(key, start, end))
asserts.AssertMultiBulkReply(t, result, members) asserts.AssertMultiBulkReply(t, result, members)
result = ZRevRange(testDB, toArgs(key, start, end)) result = ZRevRange(testDB, utils.ToBytesList(key, start, end))
asserts.AssertMultiBulkReply(t, result, reverseMembers) asserts.AssertMultiBulkReply(t, result, reverseMembers)
start = "0" start = "0"
end = "-10" end = "-10"
result = ZRange(testDB, toArgs(key, start, end)) result = ZRange(testDB, utils.ToBytesList(key, start, end))
asserts.AssertMultiBulkReply(t, result, members[0:size-10+1]) asserts.AssertMultiBulkReply(t, result, members[0:size-10+1])
result = ZRevRange(testDB, toArgs(key, start, end)) result = ZRevRange(testDB, utils.ToBytesList(key, start, end))
asserts.AssertMultiBulkReply(t, result, reverseMembers[0:size-10+1]) asserts.AssertMultiBulkReply(t, result, reverseMembers[0:size-10+1])
start = "0" start = "0"
end = "-200" end = "-200"
result = ZRange(testDB, toArgs(key, start, end)) result = ZRange(testDB, utils.ToBytesList(key, start, end))
asserts.AssertMultiBulkReply(t, result, members[0:0]) asserts.AssertMultiBulkReply(t, result, members[0:0])
result = ZRevRange(testDB, toArgs(key, start, end)) result = ZRevRange(testDB, utils.ToBytesList(key, start, end))
asserts.AssertMultiBulkReply(t, result, reverseMembers[0:0]) asserts.AssertMultiBulkReply(t, result, reverseMembers[0:0])
start = "-10" start = "-10"
end = "-1" end = "-1"
result = ZRange(testDB, toArgs(key, start, end)) result = ZRange(testDB, utils.ToBytesList(key, start, end))
asserts.AssertMultiBulkReply(t, result, members[90:]) asserts.AssertMultiBulkReply(t, result, members[90:])
result = ZRevRange(testDB, toArgs(key, start, end)) result = ZRevRange(testDB, utils.ToBytesList(key, start, end))
asserts.AssertMultiBulkReply(t, result, reverseMembers[90:]) asserts.AssertMultiBulkReply(t, result, reverseMembers[90:])
} }
@@ -143,7 +146,7 @@ func TestZRangeByScore(t *testing.T) {
// prepare // prepare
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
size := 100 size := 100
key := RandString(10) key := utils.RandString(10)
members := make([]string, size) members := make([]string, size)
scores := make([]int, size) scores := make([]int, size)
setArgs := []string{key} setArgs := []string{key}
@@ -152,48 +155,50 @@ func TestZRangeByScore(t *testing.T) {
scores[i] = i scores[i] = i
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i]) setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
} }
result := ZAdd(testDB, toArgs(setArgs...)) result := ZAdd(testDB, utils.ToBytesList(setArgs...))
min := "20" min := "20"
max := "30" max := "30"
result = ZRangeByScore(testDB, toArgs(key, min, max)) result = ZRangeByScore(testDB, utils.ToBytesList(key, min, max))
asserts.AssertMultiBulkReply(t, result, members[20:31]) asserts.AssertMultiBulkReply(t, result, members[20:31])
result = ZRevRangeByScore(testDB, toArgs(key, max, min)) result = ZRangeByScore(testDB, utils.ToBytesList(key, min, max, "WITHSCORES"))
asserts.AssertMultiBulkReplySize(t, result, 22)
result = ZRevRangeByScore(testDB, utils.ToBytesList(key, max, min))
asserts.AssertMultiBulkReply(t, result, reverse(members[20:31])) asserts.AssertMultiBulkReply(t, result, reverse(members[20:31]))
min = "-10" min = "-10"
max = "10" max = "10"
result = ZRangeByScore(testDB, toArgs(key, min, max)) result = ZRangeByScore(testDB, utils.ToBytesList(key, min, max))
asserts.AssertMultiBulkReply(t, result, members[0:11]) asserts.AssertMultiBulkReply(t, result, members[0:11])
result = ZRevRangeByScore(testDB, toArgs(key, max, min)) result = ZRevRangeByScore(testDB, utils.ToBytesList(key, max, min))
asserts.AssertMultiBulkReply(t, result, reverse(members[0:11])) asserts.AssertMultiBulkReply(t, result, reverse(members[0:11]))
min = "90" min = "90"
max = "110" max = "110"
result = ZRangeByScore(testDB, toArgs(key, min, max)) result = ZRangeByScore(testDB, utils.ToBytesList(key, min, max))
asserts.AssertMultiBulkReply(t, result, members[90:]) asserts.AssertMultiBulkReply(t, result, members[90:])
result = ZRevRangeByScore(testDB, toArgs(key, max, min)) result = ZRevRangeByScore(testDB, utils.ToBytesList(key, max, min))
asserts.AssertMultiBulkReply(t, result, reverse(members[90:])) asserts.AssertMultiBulkReply(t, result, reverse(members[90:]))
min = "(20" min = "(20"
max = "(30" max = "(30"
result = ZRangeByScore(testDB, toArgs(key, min, max)) result = ZRangeByScore(testDB, utils.ToBytesList(key, min, max))
asserts.AssertMultiBulkReply(t, result, members[21:30]) asserts.AssertMultiBulkReply(t, result, members[21:30])
result = ZRevRangeByScore(testDB, toArgs(key, max, min)) result = ZRevRangeByScore(testDB, utils.ToBytesList(key, max, min))
asserts.AssertMultiBulkReply(t, result, reverse(members[21:30])) asserts.AssertMultiBulkReply(t, result, reverse(members[21:30]))
min = "20" min = "20"
max = "40" max = "40"
result = ZRangeByScore(testDB, toArgs(key, min, max, "LIMIT", "5", "5")) result = ZRangeByScore(testDB, utils.ToBytesList(key, min, max, "LIMIT", "5", "5"))
asserts.AssertMultiBulkReply(t, result, members[25:30]) asserts.AssertMultiBulkReply(t, result, members[25:30])
result = ZRevRangeByScore(testDB, toArgs(key, max, min, "LIMIT", "5", "5")) result = ZRevRangeByScore(testDB, utils.ToBytesList(key, max, min, "LIMIT", "5", "5"))
asserts.AssertMultiBulkReply(t, result, reverse(members[31:36])) asserts.AssertMultiBulkReply(t, result, reverse(members[31:36]))
} }
func TestZRem(t *testing.T) { func TestZRem(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
size := 100 size := 100
key := RandString(10) key := utils.RandString(10)
members := make([]string, size) members := make([]string, size)
scores := make([]int, size) scores := make([]int, size)
setArgs := []string{key} setArgs := []string{key}
@@ -202,19 +207,19 @@ func TestZRem(t *testing.T) {
scores[i] = i scores[i] = i
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i]) setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
} }
ZAdd(testDB, toArgs(setArgs...)) ZAdd(testDB, utils.ToBytesList(setArgs...))
args := []string{key} args := []string{key}
args = append(args, members[0:10]...) args = append(args, members[0:10]...)
result := ZRem(testDB, toArgs(args...)) result := ZRem(testDB, utils.ToBytesList(args...))
asserts.AssertIntReply(t, result, 10) asserts.AssertIntReply(t, result, 10)
result = ZCard(testDB, toArgs(key)) result = ZCard(testDB, utils.ToBytesList(key))
asserts.AssertIntReply(t, result, size-10) asserts.AssertIntReply(t, result, size-10)
// test ZRemRangeByRank // test ZRemRangeByRank
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
size = 100 size = 100
key = RandString(10) key = utils.RandString(10)
members = make([]string, size) members = make([]string, size)
scores = make([]int, size) scores = make([]int, size)
setArgs = []string{key} setArgs = []string{key}
@@ -223,17 +228,17 @@ func TestZRem(t *testing.T) {
scores[i] = i scores[i] = i
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i]) setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
} }
ZAdd(testDB, toArgs(setArgs...)) ZAdd(testDB, utils.ToBytesList(setArgs...))
result = ZRemRangeByRank(testDB, toArgs(key, "0", "9")) result = ZRemRangeByRank(testDB, utils.ToBytesList(key, "0", "9"))
asserts.AssertIntReply(t, result, 10) asserts.AssertIntReply(t, result, 10)
result = ZCard(testDB, toArgs(key)) result = ZCard(testDB, utils.ToBytesList(key))
asserts.AssertIntReply(t, result, size-10) asserts.AssertIntReply(t, result, size-10)
// test ZRemRangeByScore // test ZRemRangeByScore
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
size = 100 size = 100
key = RandString(10) key = utils.RandString(10)
members = make([]string, size) members = make([]string, size)
scores = make([]int, size) scores = make([]int, size)
setArgs = []string{key} setArgs = []string{key}
@@ -242,11 +247,11 @@ func TestZRem(t *testing.T) {
scores[i] = i scores[i] = i
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i]) setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
} }
ZAdd(testDB, toArgs(setArgs...)) ZAdd(testDB, utils.ToBytesList(setArgs...))
result = ZRemRangeByScore(testDB, toArgs(key, "0", "9")) result = ZRemRangeByScore(testDB, utils.ToBytesList(key, "0", "9"))
asserts.AssertIntReply(t, result, 10) asserts.AssertIntReply(t, result, 10)
result = ZCard(testDB, toArgs(key)) result = ZCard(testDB, utils.ToBytesList(key))
asserts.AssertIntReply(t, result, size-10) asserts.AssertIntReply(t, result, size-10)
} }
@@ -254,7 +259,7 @@ func TestZCount(t *testing.T) {
// prepare // prepare
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
size := 100 size := 100
key := RandString(10) key := utils.RandString(10)
members := make([]string, size) members := make([]string, size)
scores := make([]int, size) scores := make([]int, size)
setArgs := []string{key} setArgs := []string{key}
@@ -263,36 +268,37 @@ func TestZCount(t *testing.T) {
scores[i] = i scores[i] = i
setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i]) setArgs = append(setArgs, strconv.FormatInt(int64(scores[i]), 10), members[i])
} }
ZAdd(testDB, toArgs(setArgs...)) ZAdd(testDB, utils.ToBytesList(setArgs...))
min := "20" min := "20"
max := "30" max := "30"
result := ZCount(testDB, toArgs(key, min, max)) result := ZCount(testDB, utils.ToBytesList(key, min, max))
asserts.AssertIntReply(t, result, 11) asserts.AssertIntReply(t, result, 11)
min = "-10" min = "-10"
max = "10" max = "10"
result = ZCount(testDB, toArgs(key, min, max)) result = ZCount(testDB, utils.ToBytesList(key, min, max))
asserts.AssertIntReply(t, result, 11) asserts.AssertIntReply(t, result, 11)
min = "90" min = "90"
max = "110" max = "110"
result = ZCount(testDB, toArgs(key, min, max)) result = ZCount(testDB, utils.ToBytesList(key, min, max))
asserts.AssertIntReply(t, result, 10) asserts.AssertIntReply(t, result, 10)
min = "(20" min = "(20"
max = "(30" max = "(30"
result = ZCount(testDB, toArgs(key, min, max)) result = ZCount(testDB, utils.ToBytesList(key, min, max))
asserts.AssertIntReply(t, result, 9) asserts.AssertIntReply(t, result, 9)
} }
func TestZIncrBy(t *testing.T) { func TestZIncrBy(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils.RandString(10)
ZAdd(testDB, toArgs(key, "10", "a")) result := ZIncrBy(testDB, utils.ToBytesList(key, "10", "a"))
result := ZIncrBy(testDB, toArgs(key, "10", "a")) asserts.AssertBulkReply(t, result, "10")
result = ZIncrBy(testDB, utils.ToBytesList(key, "10", "a"))
asserts.AssertBulkReply(t, result, "20") asserts.AssertBulkReply(t, result, "20")
result = ZScore(testDB, toArgs(key, "a")) result = ZScore(testDB, utils.ToBytesList(key, "a"))
asserts.AssertBulkReply(t, result, "20") asserts.AssertBulkReply(t, result, "20")
} }

View File

@@ -3,6 +3,7 @@ package db
import ( import (
"fmt" "fmt"
"github.com/hdt3213/godis/datastruct/utils" "github.com/hdt3213/godis/datastruct/utils"
utils2 "github.com/hdt3213/godis/lib/utils"
"github.com/hdt3213/godis/redis/reply" "github.com/hdt3213/godis/redis/reply"
"github.com/hdt3213/godis/redis/reply/asserts" "github.com/hdt3213/godis/redis/reply/asserts"
"strconv" "strconv"
@@ -13,28 +14,28 @@ var testDB = makeTestDB()
func TestSet(t *testing.T) { func TestSet(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils2.RandString(10)
value := RandString(10) value := utils2.RandString(10)
// normal set // normal set
Set(testDB, toArgs(key, value)) Set(testDB, utils2.ToBytesList(key, value))
actual := Get(testDB, toArgs(key)) actual := Get(testDB, utils2.ToBytesList(key))
expected := reply.MakeBulkReply([]byte(value)) expected := reply.MakeBulkReply([]byte(value))
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes())) t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
} }
// set nx // set nx
actual = Set(testDB, toArgs(key, value, "NX")) actual = Set(testDB, utils2.ToBytesList(key, value, "NX"))
if _, ok := actual.(*reply.NullBulkReply); !ok { if _, ok := actual.(*reply.NullBulkReply); !ok {
t.Error("expected true actual false") t.Error("expected true actual false")
} }
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key = RandString(10) key = utils2.RandString(10)
value = RandString(10) value = utils2.RandString(10)
Set(testDB, toArgs(key, value, "NX")) Set(testDB, utils2.ToBytesList(key, value, "NX"))
actual = Get(testDB, toArgs(key)) actual = Get(testDB, utils2.ToBytesList(key))
expected = reply.MakeBulkReply([]byte(value)) expected = reply.MakeBulkReply([]byte(value))
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes())) t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
@@ -42,25 +43,25 @@ func TestSet(t *testing.T) {
// set xx // set xx
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key = RandString(10) key = utils2.RandString(10)
value = RandString(10) value = utils2.RandString(10)
actual = Set(testDB, toArgs(key, value, "XX")) actual = Set(testDB, utils2.ToBytesList(key, value, "XX"))
if _, ok := actual.(*reply.NullBulkReply); !ok { if _, ok := actual.(*reply.NullBulkReply); !ok {
t.Error("expected true actually false ") t.Error("expected true actually false ")
} }
Set(testDB, toArgs(key, value)) Set(testDB, utils2.ToBytesList(key, value))
Set(testDB, toArgs(key, value, "XX")) Set(testDB, utils2.ToBytesList(key, value, "XX"))
actual = Get(testDB, toArgs(key)) actual = Get(testDB, utils2.ToBytesList(key))
asserts.AssertBulkReply(t, actual, value) asserts.AssertBulkReply(t, actual, value)
// set ex // set ex
Del(testDB, toArgs(key)) Del(testDB, utils2.ToBytesList(key))
ttl := "1000" ttl := "1000"
Set(testDB, toArgs(key, value, "EX", ttl)) Set(testDB, utils2.ToBytesList(key, value, "EX", ttl))
actual = Get(testDB, toArgs(key)) actual = Get(testDB, utils2.ToBytesList(key))
asserts.AssertBulkReply(t, actual, value) asserts.AssertBulkReply(t, actual, value)
actual = TTL(testDB, toArgs(key)) actual = TTL(testDB, utils2.ToBytesList(key))
intResult, ok := actual.(*reply.IntReply) intResult, ok := actual.(*reply.IntReply)
if !ok { if !ok {
t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes())) t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes()))
@@ -72,12 +73,12 @@ func TestSet(t *testing.T) {
} }
// set px // set px
Del(testDB, toArgs(key)) Del(testDB, utils2.ToBytesList(key))
ttlPx := "1000000" ttlPx := "1000000"
Set(testDB, toArgs(key, value, "PX", ttlPx)) Set(testDB, utils2.ToBytesList(key, value, "PX", ttlPx))
actual = Get(testDB, toArgs(key)) actual = Get(testDB, utils2.ToBytesList(key))
asserts.AssertBulkReply(t, actual, value) asserts.AssertBulkReply(t, actual, value)
actual = TTL(testDB, toArgs(key)) actual = TTL(testDB, utils2.ToBytesList(key))
intResult, ok = actual.(*reply.IntReply) intResult, ok = actual.(*reply.IntReply)
if !ok { if !ok {
t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes())) t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes()))
@@ -91,16 +92,16 @@ func TestSet(t *testing.T) {
func TestSetNX(t *testing.T) { func TestSetNX(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils2.RandString(10)
value := RandString(10) value := utils2.RandString(10)
SetNX(testDB, toArgs(key, value)) SetNX(testDB, utils2.ToBytesList(key, value))
actual := Get(testDB, toArgs(key)) actual := Get(testDB, utils2.ToBytesList(key))
expected := reply.MakeBulkReply([]byte(value)) expected := reply.MakeBulkReply([]byte(value))
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes())) t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
} }
actual = SetNX(testDB, toArgs(key, value)) actual = SetNX(testDB, utils2.ToBytesList(key, value))
expected2 := reply.MakeIntReply(int64(0)) expected2 := reply.MakeIntReply(int64(0))
if !utils.BytesEquals(actual.ToBytes(), expected2.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected2.ToBytes()) {
t.Error("expected: " + string(expected2.ToBytes()) + ", actual: " + string(actual.ToBytes())) t.Error("expected: " + string(expected2.ToBytes()) + ", actual: " + string(actual.ToBytes()))
@@ -109,14 +110,14 @@ func TestSetNX(t *testing.T) {
func TestSetEX(t *testing.T) { func TestSetEX(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils2.RandString(10)
value := RandString(10) value := utils2.RandString(10)
ttl := "1000" ttl := "1000"
SetEX(testDB, toArgs(key, ttl, value)) SetEX(testDB, utils2.ToBytesList(key, ttl, value))
actual := Get(testDB, toArgs(key)) actual := Get(testDB, utils2.ToBytesList(key))
asserts.AssertBulkReply(t, actual, value) asserts.AssertBulkReply(t, actual, value)
actual = TTL(testDB, toArgs(key)) actual = TTL(testDB, utils2.ToBytesList(key))
intResult, ok := actual.(*reply.IntReply) intResult, ok := actual.(*reply.IntReply)
if !ok { if !ok {
t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes())) t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes()))
@@ -130,14 +131,14 @@ func TestSetEX(t *testing.T) {
func TestPSetEX(t *testing.T) { func TestPSetEX(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils2.RandString(10)
value := RandString(10) value := utils2.RandString(10)
ttl := "1000000" ttl := "1000000"
PSetEX(testDB, toArgs(key, ttl, value)) PSetEX(testDB, utils2.ToBytesList(key, ttl, value))
actual := Get(testDB, toArgs(key)) actual := Get(testDB, utils2.ToBytesList(key))
asserts.AssertBulkReply(t, actual, value) asserts.AssertBulkReply(t, actual, value)
actual = PTTL(testDB, toArgs(key)) actual = PTTL(testDB, utils2.ToBytesList(key))
intResult, ok := actual.(*reply.IntReply) intResult, ok := actual.(*reply.IntReply)
if !ok { if !ok {
t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes())) t.Error(fmt.Sprintf("expected int reply, actually %s", actual.ToBytes()))
@@ -156,13 +157,13 @@ func TestMSet(t *testing.T) {
values := make([][]byte, size) values := make([][]byte, size)
args := make([]string, 0, size*2) args := make([]string, 0, size*2)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
keys[i] = RandString(10) keys[i] = utils2.RandString(10)
value := RandString(10) value := utils2.RandString(10)
values[i] = []byte(value) values[i] = []byte(value)
args = append(args, keys[i], value) args = append(args, keys[i], value)
} }
MSet(testDB, toArgs(args...)) MSet(testDB, utils2.ToBytesList(args...))
actual := MGet(testDB, toArgs(keys...)) actual := MGet(testDB, utils2.ToBytesList(keys...))
expected := reply.MakeMultiBulkReply(values) expected := reply.MakeMultiBulkReply(values)
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes())) t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
@@ -172,18 +173,18 @@ func TestMSet(t *testing.T) {
func TestIncr(t *testing.T) { func TestIncr(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
size := 10 size := 10
key := RandString(10) key := utils2.RandString(10)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
Incr(testDB, toArgs(key)) Incr(testDB, utils2.ToBytesList(key))
actual := Get(testDB, toArgs(key)) actual := Get(testDB, utils2.ToBytesList(key))
expected := reply.MakeBulkReply([]byte(strconv.FormatInt(int64(i+1), 10))) expected := reply.MakeBulkReply([]byte(strconv.FormatInt(int64(i+1), 10)))
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes())) t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
} }
} }
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
IncrBy(testDB, toArgs(key, "-1")) IncrBy(testDB, utils2.ToBytesList(key, "-1"))
actual := Get(testDB, toArgs(key)) actual := Get(testDB, utils2.ToBytesList(key))
expected := reply.MakeBulkReply([]byte(strconv.FormatInt(int64(size-i-1), 10))) expected := reply.MakeBulkReply([]byte(strconv.FormatInt(int64(size-i-1), 10)))
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes())) t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
@@ -191,19 +192,19 @@ func TestIncr(t *testing.T) {
} }
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key = RandString(10) key = utils2.RandString(10)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
IncrBy(testDB, toArgs(key, "1")) IncrBy(testDB, utils2.ToBytesList(key, "1"))
actual := Get(testDB, toArgs(key)) actual := Get(testDB, utils2.ToBytesList(key))
expected := reply.MakeBulkReply([]byte(strconv.FormatInt(int64(i+1), 10))) expected := reply.MakeBulkReply([]byte(strconv.FormatInt(int64(i+1), 10)))
if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) { if !utils.BytesEquals(actual.ToBytes(), expected.ToBytes()) {
t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes())) t.Error("expected: " + string(expected.ToBytes()) + ", actual: " + string(actual.ToBytes()))
} }
} }
Del(testDB, toArgs(key)) Del(testDB, utils2.ToBytesList(key))
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
IncrByFloat(testDB, toArgs(key, "-1.0")) IncrByFloat(testDB, utils2.ToBytesList(key, "-1.0"))
actual := Get(testDB, toArgs(key)) actual := Get(testDB, utils2.ToBytesList(key))
expected := -i - 1 expected := -i - 1
bulk, ok := actual.(*reply.BulkReply) bulk, ok := actual.(*reply.BulkReply)
if !ok { if !ok {
@@ -225,16 +226,16 @@ func TestIncr(t *testing.T) {
func TestDecr(t *testing.T) { func TestDecr(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
size := 10 size := 10
key := RandString(10) key := utils2.RandString(10)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
Decr(testDB, toArgs(key)) Decr(testDB, utils2.ToBytesList(key))
actual := Get(testDB, toArgs(key)) actual := Get(testDB, utils2.ToBytesList(key))
asserts.AssertBulkReply(t, actual, strconv.Itoa(-i-1)) asserts.AssertBulkReply(t, actual, strconv.Itoa(-i-1))
} }
Del(testDB, toArgs(key)) Del(testDB, utils2.ToBytesList(key))
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
DecrBy(testDB, toArgs(key, "1")) DecrBy(testDB, utils2.ToBytesList(key, "1"))
actual := Get(testDB, toArgs(key)) actual := Get(testDB, utils2.ToBytesList(key))
expected := -i - 1 expected := -i - 1
bulk, ok := actual.(*reply.BulkReply) bulk, ok := actual.(*reply.BulkReply)
if !ok { if !ok {
@@ -255,20 +256,20 @@ func TestDecr(t *testing.T) {
func TestGetSet(t *testing.T) { func TestGetSet(t *testing.T) {
FlushAll(testDB, [][]byte{}) FlushAll(testDB, [][]byte{})
key := RandString(10) key := utils2.RandString(10)
value := RandString(10) value := utils2.RandString(10)
result := GetSet(testDB, toArgs(key, value)) result := GetSet(testDB, utils2.ToBytesList(key, value))
_, ok := result.(*reply.NullBulkReply) _, ok := result.(*reply.NullBulkReply)
if !ok { if !ok {
t.Errorf("expect null bulk reply, get: %s", string(result.ToBytes())) t.Errorf("expect null bulk reply, get: %s", string(result.ToBytes()))
return return
} }
value2 := RandString(10) value2 := utils2.RandString(10)
result = GetSet(testDB, toArgs(key, value2)) result = GetSet(testDB, utils2.ToBytesList(key, value2))
asserts.AssertBulkReply(t, result, value) asserts.AssertBulkReply(t, result, value)
result = Get(testDB, toArgs(key)) result = Get(testDB, utils2.ToBytesList(key))
asserts.AssertBulkReply(t, result, value2) asserts.AssertBulkReply(t, result, value2)
} }
@@ -277,12 +278,12 @@ func TestMSetNX(t *testing.T) {
size := 10 size := 10
args := make([]string, 0, size*2) args := make([]string, 0, size*2)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
str := RandString(10) str := utils2.RandString(10)
args = append(args, str, str) args = append(args, str, str)
} }
result := MSetNX(testDB, toArgs(args...)) result := MSetNX(testDB, utils2.ToBytesList(args...))
asserts.AssertIntReply(t, result, 1) asserts.AssertIntReply(t, result, 1)
result = MSetNX(testDB, toArgs(args[0:4]...)) result = MSetNX(testDB, utils2.ToBytesList(args[0:4]...))
asserts.AssertIntReply(t, result, 0) asserts.AssertIntReply(t, result, 0)
} }

View File

@@ -3,7 +3,6 @@ package db
import ( import (
"github.com/hdt3213/godis/datastruct/dict" "github.com/hdt3213/godis/datastruct/dict"
"github.com/hdt3213/godis/datastruct/lock" "github.com/hdt3213/godis/datastruct/lock"
"math/rand"
) )
func makeTestDB() *DB { func makeTestDB() *DB {
@@ -14,20 +13,3 @@ func makeTestDB() *DB {
} }
} }
func toArgs(cmd ...string) [][]byte {
args := make([][]byte, len(cmd))
for i, s := range cmd {
args[i] = []byte(s)
}
return args
}
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
func RandString(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}

View File

@@ -0,0 +1,20 @@
package timewheel
import (
"testing"
"time"
)
func TestDelay(t *testing.T) {
ch := make(chan time.Time)
beginTime := time.Now()
Delay(time.Second, "", func() {
ch <- time.Now()
})
execAt := <-ch
delayDuration := execAt.Sub(beginTime)
// usually 1.0~2.0 s
if delayDuration < time.Second || delayDuration > 3*time.Second {
t.Error("wrong execute time")
}
}

9
lib/utils/convert.go Normal file
View File

@@ -0,0 +1,9 @@
package utils
func ToBytesList(cmd ...string) [][]byte {
args := make([][]byte, len(cmd))
for i, s := range cmd {
args[i] = []byte(s)
}
return args
}

13
lib/utils/rand_string.go Normal file
View File

@@ -0,0 +1,13 @@
package utils
import "math/rand"
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
func RandString(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}

View File

@@ -3,7 +3,11 @@ package wildcard
import "testing" import "testing"
func TestWildCard(t *testing.T) { func TestWildCard(t *testing.T) {
p := CompilePattern("a") p := CompilePattern("")
if !p.IsMatch("") {
t.Error("expect true actually false")
}
p = CompilePattern("a")
if !p.IsMatch("a") { if !p.IsMatch("a") {
t.Error("expect true actually false") t.Error("expect true actually false")
} }

View File

@@ -121,6 +121,7 @@ func UnSubscribe(db *Hub, c redis.Connection, args [][]byte) redis.Reply {
return &reply.NoReply{} return &reply.NoReply{}
} }
// Publish send msg to all subscribing client
func Publish(hub *Hub, args [][]byte) redis.Reply { func Publish(hub *Hub, args [][]byte) redis.Reply {
if len(args) != 2 { if len(args) != 2 {
return &reply.ArgNumErrReply{Cmd: "publish"} return &reply.ArgNumErrReply{Cmd: "publish"}

View File

@@ -184,7 +184,7 @@ func (client *Client) finishRequest(reply redis.Reply) {
} }
func (client *Client) handleRead() error { func (client *Client) handleRead() error {
ch := parser.Parse(client.conn) ch := parser.ParseStream(client.conn)
for payload := range ch { for payload := range ch {
if payload.Err != nil { if payload.Err != nil {
client.finishRequest(reply.MakeErrReply(payload.Err.Error())) client.finishRequest(reply.MakeErrReply(payload.Err.Error()))

View File

@@ -1,6 +1,7 @@
package server package connection
import ( import (
"bytes"
"github.com/hdt3213/godis/lib/sync/wait" "github.com/hdt3213/godis/lib/sync/wait"
"net" "net"
"sync" "sync"
@@ -21,6 +22,11 @@ type Connection struct {
subs map[string]bool subs map[string]bool
} }
// RemoteAddr returns the remote network address
func (c *Connection) RemoteAddr() net.Addr {
return c.conn.RemoteAddr()
}
// Close disconnect with the client // Close disconnect with the client
func (c *Connection) Close() error { func (c *Connection) Close() error {
c.waitingReply.WaitWithTimeout(10 * time.Second) c.waitingReply.WaitWithTimeout(10 * time.Second)
@@ -90,3 +96,21 @@ func (c *Connection) GetChannels() []string {
} }
return channels return channels
} }
type FakeConn struct {
Connection
buf bytes.Buffer
}
func (c *FakeConn) Write(b []byte) error {
c.buf.Write(b)
return nil
}
func (c *FakeConn) Clean() {
c.buf.Reset()
}
func (c *FakeConn) Bytes() []byte {
return c.buf.Bytes()
}

View File

@@ -2,6 +2,7 @@ package parser
import ( import (
"bufio" "bufio"
"bytes"
"errors" "errors"
"github.com/hdt3213/godis/interface/redis" "github.com/hdt3213/godis/interface/redis"
"github.com/hdt3213/godis/lib/logger" "github.com/hdt3213/godis/lib/logger"
@@ -17,19 +18,25 @@ type Payload struct {
Err error Err error
} }
func Parse(reader io.Reader) <-chan *Payload { // ParseStream reads data from io.Reader and send payloads through channel
func ParseStream(reader io.Reader) <-chan *Payload {
ch := make(chan *Payload) ch := make(chan *Payload)
go func() { go parse0(reader, ch)
defer func() {
if err := recover(); err != nil {
logger.Error(debug.Stack())
}
}()
parse0(reader, ch)
}()
return ch return ch
} }
// ParseOne reads data from []byte and return the first payload
func ParseOne(data []byte) (redis.Reply, error) {
ch := make(chan *Payload)
reader := bytes.NewReader(data)
go parse0(reader, ch)
payload := <-ch // parse0 will close the channel
if payload == nil {
return nil, errors.New("no reply")
}
return payload.Data, payload.Err
}
type readState struct { type readState struct {
downloading bool downloading bool
expectedArgsCount int expectedArgsCount int
@@ -44,6 +51,11 @@ func (s *readState) finished() bool {
} }
func parse0(reader io.Reader, ch chan<- *Payload) { func parse0(reader io.Reader, ch chan<- *Payload) {
defer func() {
if err := recover(); err != nil {
logger.Error(string(debug.Stack()))
}
}()
bufReader := bufio.NewReader(reader) bufReader := bufio.NewReader(reader)
var state readState var state readState
var err error var err error

View File

@@ -9,7 +9,7 @@ import (
"testing" "testing"
) )
func TestParse(t *testing.T) { func TestParseStream(t *testing.T) {
replies := []redis.Reply{ replies := []redis.Reply{
reply.MakeIntReply(1), reply.MakeIntReply(1),
reply.MakeStatusReply("OK"), reply.MakeStatusReply("OK"),
@@ -33,7 +33,7 @@ func TestParse(t *testing.T) {
[]byte("set"), []byte("a"), []byte("a"), []byte("set"), []byte("a"), []byte("a"),
})) }))
ch := Parse(bytes.NewReader(reqs.Bytes())) ch := ParseStream(bytes.NewReader(reqs.Bytes()))
i := 0 i := 0
for payload := range ch { for payload := range ch {
if payload.Err != nil { if payload.Err != nil {
@@ -54,3 +54,28 @@ func TestParse(t *testing.T) {
} }
} }
} }
func TestParseOne(t *testing.T) {
replies := []redis.Reply{
reply.MakeIntReply(1),
reply.MakeStatusReply("OK"),
reply.MakeErrReply("ERR unknown"),
reply.MakeBulkReply([]byte("a\r\nb")), // test binary safe
reply.MakeNullBulkReply(),
reply.MakeMultiBulkReply([][]byte{
[]byte("a"),
[]byte("\r\n"),
}),
reply.MakeEmptyMultiBulkReply(),
}
for _, re := range replies {
result, err := ParseOne(re.ToBytes())
if err != nil {
t.Error(err)
continue
}
if !utils.BytesEquals(result.ToBytes(), re.ToBytes()) {
t.Error("parse failed: " + string(re.ToBytes()))
}
}
}

View File

@@ -115,6 +115,10 @@ func AssertMultiBulkReply(t *testing.T, actual redis.Reply, expected []string) {
func AssertMultiBulkReplySize(t *testing.T, actual redis.Reply, expected int) { func AssertMultiBulkReplySize(t *testing.T, actual redis.Reply, expected int) {
multiBulk, ok := actual.(*reply.MultiBulkReply) multiBulk, ok := actual.(*reply.MultiBulkReply)
if !ok { if !ok {
if expected == 0 &&
utils.BytesEquals(actual.ToBytes(), reply.MakeEmptyMultiBulkReply().ToBytes()) {
return
}
t.Errorf("expected bulk reply, actually %s, %s", actual.ToBytes(), printStack()) t.Errorf("expected bulk reply, actually %s, %s", actual.ToBytes(), printStack())
return return
} }

View File

@@ -0,0 +1,50 @@
package server
import (
"github.com/hdt3213/godis/lib/utils"
"github.com/hdt3213/godis/pubsub"
"github.com/hdt3213/godis/redis/connection"
"github.com/hdt3213/godis/redis/parser"
"github.com/hdt3213/godis/redis/reply/asserts"
"testing"
)
func TestPublish(t *testing.T) {
hub := pubsub.MakeHub()
channel := utils.RandString(5)
msg := utils.RandString(5)
conn := &connection.FakeConn{}
pubsub.Subscribe(hub, conn, utils.ToBytesList(channel))
conn.Clean() // clean subscribe success
pubsub.Publish(hub, utils.ToBytesList(channel, msg))
data := conn.Bytes()
ret, err := parser.ParseOne(data)
if err != nil {
t.Error(err)
return
}
asserts.AssertMultiBulkReply(t, ret, []string{
"message",
channel,
msg,
})
// unsubscribe
pubsub.UnSubscribe(hub, conn, utils.ToBytesList(channel))
conn.Clean()
pubsub.Publish(hub, utils.ToBytesList(channel, msg))
data = conn.Bytes()
if len(data) > 0 {
t.Error("expect no msg")
}
// unsubscribe all
pubsub.Subscribe(hub, conn, utils.ToBytesList(channel))
pubsub.UnSubscribe(hub, conn, utils.ToBytesList())
conn.Clean()
pubsub.Publish(hub, utils.ToBytesList(channel, msg))
data = conn.Bytes()
if len(data) > 0 {
t.Error("expect no msg")
}
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/hdt3213/godis/interface/db" "github.com/hdt3213/godis/interface/db"
"github.com/hdt3213/godis/lib/logger" "github.com/hdt3213/godis/lib/logger"
"github.com/hdt3213/godis/lib/sync/atomic" "github.com/hdt3213/godis/lib/sync/atomic"
"github.com/hdt3213/godis/redis/connection"
"github.com/hdt3213/godis/redis/parser" "github.com/hdt3213/godis/redis/parser"
"github.com/hdt3213/godis/redis/reply" "github.com/hdt3213/godis/redis/reply"
"io" "io"
@@ -45,7 +46,7 @@ func MakeHandler() *Handler {
} }
} }
func (h *Handler) closeClient(client *Connection) { func (h *Handler) closeClient(client *connection.Connection) {
_ = client.Close() _ = client.Close()
h.db.AfterClientClose(client) h.db.AfterClientClose(client)
h.activeConn.Delete(client) h.activeConn.Delete(client)
@@ -58,10 +59,10 @@ func (h *Handler) Handle(ctx context.Context, conn net.Conn) {
_ = conn.Close() _ = conn.Close()
} }
client := NewConn(conn) client := connection.NewConn(conn)
h.activeConn.Store(client, 1) h.activeConn.Store(client, 1)
ch := parser.Parse(conn) ch := parser.ParseStream(conn)
for payload := range ch { for payload := range ch {
if payload.Err != nil { if payload.Err != nil {
if payload.Err == io.EOF || if payload.Err == io.EOF ||
@@ -69,7 +70,7 @@ func (h *Handler) Handle(ctx context.Context, conn net.Conn) {
strings.Contains(payload.Err.Error(), "use of closed network connection") { strings.Contains(payload.Err.Error(), "use of closed network connection") {
// connection closed // connection closed
h.closeClient(client) h.closeClient(client)
logger.Info("connection closed: " + client.conn.RemoteAddr().String()) logger.Info("connection closed: " + client.RemoteAddr().String())
return return
} else { } else {
// protocol err // protocol err
@@ -77,7 +78,7 @@ func (h *Handler) Handle(ctx context.Context, conn net.Conn) {
err := client.Write(errReply.ToBytes()) err := client.Write(errReply.ToBytes())
if err != nil { if err != nil {
h.closeClient(client) h.closeClient(client)
logger.Info("connection closed: " + client.conn.RemoteAddr().String()) logger.Info("connection closed: " + client.RemoteAddr().String())
return return
} }
continue continue
@@ -107,7 +108,7 @@ func (h *Handler) Close() error {
h.closing.Set(true) h.closing.Set(true)
// TODO: concurrent wait // TODO: concurrent wait
h.activeConn.Range(func(key interface{}, val interface{}) bool { h.activeConn.Range(func(key interface{}, val interface{}) bool {
client := key.(*Connection) client := key.(*connection.Connection)
_ = client.Close() _ = client.Close()
return true return true
}) })

View File

@@ -5,6 +5,7 @@ import (
"github.com/hdt3213/godis/tcp" "github.com/hdt3213/godis/tcp"
"net" "net"
"testing" "testing"
"time"
) )
func TestListenAndServe(t *testing.T) { func TestListenAndServe(t *testing.T) {
@@ -39,4 +40,5 @@ func TestListenAndServe(t *testing.T) {
return return
} }
closeChan <- struct{}{} closeChan <- struct{}{}
time.Sleep(time.Second)
} }

View File

@@ -6,6 +6,7 @@ import (
"net" "net"
"strconv" "strconv"
"testing" "testing"
"time"
) )
func TestListenAndServe(t *testing.T) { func TestListenAndServe(t *testing.T) {
@@ -42,5 +43,11 @@ func TestListenAndServe(t *testing.T) {
return return
} }
} }
_ = conn.Close()
for i := 0; i < 5; i++ {
// create idle connection
_, _ = net.Dial("tcp", addr)
}
closeChan <- struct{}{} closeChan <- struct{}{}
time.Sleep(time.Second)
} }