Files
redis-go/database/set_test.go
2024-07-29 13:59:18 +08:00

288 lines
8.3 KiB
Go

package database
import (
"github.com/hdt3213/godis/lib/utils"
"github.com/hdt3213/godis/redis/protocol"
"github.com/hdt3213/godis/redis/protocol/asserts"
"math/rand"
"strconv"
"testing"
)
// basic add get and remove
func TestSAdd(t *testing.T) {
testDB.Flush()
size := 100
// test sadd
key := utils.RandString(10)
for i := 0; i < size; i++ {
member := strconv.Itoa(i)
result := testDB.Exec(nil, utils.ToCmdLine("sadd", key, member))
asserts.AssertIntReply(t, result, 1)
}
// test scard
result := testDB.Exec(nil, utils.ToCmdLine("SCard", key))
asserts.AssertIntReply(t, result, size)
// test is member
for i := 0; i < size; i++ {
member := strconv.Itoa(i)
result = testDB.Exec(nil, utils.ToCmdLine("SIsMember", key, member))
asserts.AssertIntReply(t, result, 1)
}
// test members
result = testDB.Exec(nil, utils.ToCmdLine("SMembers", key))
multiBulk, ok := result.(*protocol.MultiBulkReply)
if !ok {
t.Errorf("expected bulk protocol, actually %s", result.ToBytes())
return
}
if len(multiBulk.Args) != size {
t.Errorf("expected %d elements, actually %d", size, len(multiBulk.Args))
return
}
}
func TestSRem(t *testing.T) {
testDB.Flush()
size := 100
// mock data
key := utils.RandString(10)
for i := 0; i < size; i++ {
member := strconv.Itoa(i)
testDB.Exec(nil, utils.ToCmdLine("sadd", key, member))
}
for i := 0; i < size; i++ {
member := strconv.Itoa(i)
testDB.Exec(nil, utils.ToCmdLine("srem", key, member))
result := testDB.Exec(nil, utils.ToCmdLine("SIsMember", key, member))
asserts.AssertIntReply(t, result, 0)
}
}
func TestSPop(t *testing.T) {
testDB.Flush()
size := 100
// mock data
key := utils.RandString(10)
for i := 0; i < size; i++ {
member := strconv.Itoa(i)
testDB.Exec(nil, utils.ToCmdLine("sadd", key, member))
}
result := testDB.Exec(nil, utils.ToCmdLine("spop", key))
asserts.AssertMultiBulkReplySize(t, result, 1)
currentSize := size - 1
for currentSize > 0 {
count := rand.Intn(currentSize) + 1
resultSpop := testDB.Exec(nil, utils.ToCmdLine("spop", key, strconv.FormatInt(int64(count), 10)))
multiBulk, ok := resultSpop.(*protocol.MultiBulkReply)
if !ok {
t.Errorf("expected bulk protocol, actually %s", resultSpop.ToBytes())
return
}
removedSize := len(multiBulk.Args)
for _, arg := range multiBulk.Args {
resultSIsMember := testDB.Exec(nil, utils.ToCmdLine("SIsMember", key, string(arg)))
asserts.AssertIntReply(t, resultSIsMember, 0)
}
currentSize -= removedSize
resultSCard := testDB.Exec(nil, utils.ToCmdLine("SCard", key))
asserts.AssertIntReply(t, resultSCard, currentSize)
}
}
func TestSInter(t *testing.T) {
testDB.Flush()
size := 100
step := 10
keys := make([]string, 0)
start := 0
for i := 0; i < 4; i++ {
key := utils.RandString(10) + strconv.Itoa(i)
keys = append(keys, key)
for j := start; j < size+start; j++ {
member := strconv.Itoa(j)
testDB.Exec(nil, utils.ToCmdLine("sadd", key, member))
}
start += step
}
result := testDB.Exec(nil, utils.ToCmdLine2("sinter", keys...))
asserts.AssertMultiBulkReplySize(t, result, 70)
destKey := utils.RandString(10)
keysWithDest := []string{destKey}
keysWithDest = append(keysWithDest, keys...)
result = testDB.Exec(nil, utils.ToCmdLine2("SInterStore", keysWithDest...))
asserts.AssertIntReply(t, result, 70)
// test empty set
testDB.Flush()
key0 := utils.RandString(10)
testDB.Remove(key0)
key1 := utils.RandString(10)
testDB.Exec(nil, utils.ToCmdLine("sadd", key1, "a", "b"))
key2 := utils.RandString(10)
testDB.Exec(nil, utils.ToCmdLine("sadd", key2, "1", "2"))
result = testDB.Exec(nil, utils.ToCmdLine("sinter", key0, key1, key2))
asserts.AssertMultiBulkReplySize(t, result, 0)
result = testDB.Exec(nil, utils.ToCmdLine("sinter", key1, key2))
asserts.AssertMultiBulkReplySize(t, result, 0)
result = testDB.Exec(nil, utils.ToCmdLine("sinterstore", utils.RandString(10), key0, key1, key2))
asserts.AssertIntReply(t, result, 0)
result = testDB.Exec(nil, utils.ToCmdLine("sinterstore", utils.RandString(10), key1, key2))
asserts.AssertIntReply(t, result, 0)
}
func TestSUnion(t *testing.T) {
testDB.Flush()
size := 100
step := 10
keys := make([]string, 0)
start := 0
for i := 0; i < 4; i++ {
key := utils.RandString(10)
keys = append(keys, key)
for j := start; j < size+start; j++ {
member := strconv.Itoa(j)
testDB.Exec(nil, utils.ToCmdLine("sadd", key, member))
}
start += step
}
result := testDB.Exec(nil, utils.ToCmdLine2("sunion", keys...))
asserts.AssertMultiBulkReplySize(t, result, 130)
destKey := utils.RandString(10)
keysWithDest := []string{destKey}
keysWithDest = append(keysWithDest, keys...)
result = testDB.Exec(nil, utils.ToCmdLine2("SUnionStore", keysWithDest...))
asserts.AssertIntReply(t, result, 130)
}
func TestSDiff(t *testing.T) {
testDB.Flush()
size := 100
step := 20
keys := make([]string, 0)
start := 0
for i := 0; i < 3; i++ {
key := utils.RandString(10)
keys = append(keys, key)
for j := start; j < size+start; j++ {
member := strconv.Itoa(j)
testDB.Exec(nil, utils.ToCmdLine("sadd", key, member))
}
start += step
}
result := testDB.Exec(nil, utils.ToCmdLine2("SDiff", keys...))
asserts.AssertMultiBulkReplySize(t, result, step)
destKey := utils.RandString(10)
keysWithDest := []string{destKey}
keysWithDest = append(keysWithDest, keys...)
result = testDB.Exec(nil, utils.ToCmdLine2("SDiffStore", keysWithDest...))
asserts.AssertIntReply(t, result, step)
// test empty set
testDB.Flush()
key0 := utils.RandString(10)
testDB.Remove(key0)
key1 := utils.RandString(10)
testDB.Exec(nil, utils.ToCmdLine("sadd", key1, "a", "b"))
key2 := utils.RandString(10)
testDB.Exec(nil, utils.ToCmdLine("sadd", key2, "a", "b"))
result = testDB.Exec(nil, utils.ToCmdLine("sdiff", key0, key1, key2))
asserts.AssertMultiBulkReplySize(t, result, 0)
result = testDB.Exec(nil, utils.ToCmdLine("sdiff", key1, key2))
asserts.AssertMultiBulkReplySize(t, result, 0)
result = testDB.Exec(nil, utils.ToCmdLine("SDiffStore", utils.RandString(10), key0, key1, key2))
asserts.AssertIntReply(t, result, 0)
result = testDB.Exec(nil, utils.ToCmdLine("SDiffStore", utils.RandString(10), key1, key2))
asserts.AssertIntReply(t, result, 0)
}
func TestSRandMember(t *testing.T) {
testDB.Flush()
key := utils.RandString(10)
for j := 0; j < 100; j++ {
member := strconv.Itoa(j)
testDB.Exec(nil, utils.ToCmdLine("sadd", key, member))
}
result := testDB.Exec(nil, utils.ToCmdLine("SRandMember", key))
br, ok := result.(*protocol.BulkReply)
if !ok && len(br.Arg) > 0 {
t.Errorf("expected bulk protocol, actually %s", result.ToBytes())
return
}
result = testDB.Exec(nil, utils.ToCmdLine("SRandMember", key, "10"))
asserts.AssertMultiBulkReplySize(t, result, 10)
multiBulk, ok := result.(*protocol.MultiBulkReply)
if !ok {
t.Errorf("expected bulk protocol, actually %s", result.ToBytes())
return
}
m := make(map[string]struct{})
for _, arg := range multiBulk.Args {
m[string(arg)] = struct{}{}
}
if len(m) != 10 {
t.Errorf("expected 10 members, actually %d", len(m))
return
}
result = testDB.Exec(nil, utils.ToCmdLine("SRandMember", key, "110"))
asserts.AssertMultiBulkReplySize(t, result, 100)
result = testDB.Exec(nil, utils.ToCmdLine("SRandMember", key, "-10"))
asserts.AssertMultiBulkReplySize(t, result, 10)
result = testDB.Exec(nil, utils.ToCmdLine("SRandMember", key, "-110"))
asserts.AssertMultiBulkReplySize(t, result, 110)
}
func TestSScan(t *testing.T) {
testDB.Flush()
setKey := "test:set"
for i := 0; i < 3; i++ {
key := string(rune(i))
testDB.Exec(nil, utils.ToCmdLine("sadd", setKey, "a"+key))
}
for i := 0; i < 3; i++ {
key := string(rune(i))
testDB.Exec(nil, utils.ToCmdLine("sadd", setKey, "b"+key))
}
result := testDB.Exec(nil, utils.ToCmdLine("sscan", setKey, "0", "count", "10"))
cursorStr := string(result.(*protocol.MultiRawReply).Replies[0].(*protocol.BulkReply).Arg)
cursor, err := strconv.Atoi(cursorStr)
if err == nil {
if cursor != 0 {
t.Errorf("expect cursor 0, actually %d", cursor)
return
}
} else {
t.Errorf("get scan result error")
return
}
// test sscan 0 match a*
result = testDB.Exec(nil, utils.ToCmdLine("sscan", setKey, "0", "match", "a*"))
returnKeys := result.(*protocol.MultiRawReply).Replies[1].(*protocol.MultiBulkReply).Args
for i := range returnKeys {
key := string(returnKeys[i])
if key[0] != 'a' {
t.Errorf("The key %s should match a*", key)
return
}
}
}