mirror of
https://github.com/nalgeon/redka.git
synced 2025-09-27 04:16:00 +08:00
288 lines
6.3 KiB
Go
288 lines
6.3 KiB
Go
package key
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/nalgeon/be"
|
|
"github.com/nalgeon/redka/internal/rkey"
|
|
"github.com/nalgeon/redka/redsrv/internal/redis"
|
|
)
|
|
|
|
func TestScanParse(t *testing.T) {
|
|
tests := []struct {
|
|
cmd string
|
|
cursor int
|
|
match string
|
|
ktype string
|
|
count int
|
|
err error
|
|
}{
|
|
{
|
|
cmd: "scan",
|
|
cursor: 0,
|
|
match: "*",
|
|
count: 0,
|
|
err: redis.ErrInvalidArgNum,
|
|
},
|
|
{
|
|
cmd: "scan 15",
|
|
cursor: 15,
|
|
match: "*",
|
|
count: 0,
|
|
err: nil,
|
|
},
|
|
{
|
|
cmd: "scan 15 match *",
|
|
cursor: 15,
|
|
match: "*",
|
|
count: 0,
|
|
err: nil,
|
|
},
|
|
{
|
|
cmd: "scan 15 match * count 5",
|
|
cursor: 15,
|
|
match: "*",
|
|
count: 5,
|
|
err: nil,
|
|
},
|
|
{
|
|
cmd: "scan 15 match * count ok",
|
|
cursor: 15,
|
|
match: "*",
|
|
count: 0,
|
|
err: redis.ErrInvalidInt,
|
|
},
|
|
{
|
|
cmd: "scan 15 count 5 match *",
|
|
cursor: 15,
|
|
match: "*",
|
|
count: 5,
|
|
err: nil,
|
|
},
|
|
{
|
|
cmd: "scan 15 match k2* count 5",
|
|
cursor: 15,
|
|
match: "k2*",
|
|
count: 5,
|
|
err: nil,
|
|
},
|
|
{
|
|
cmd: "scan 15 match k2* type string",
|
|
cursor: 15,
|
|
match: "k2*",
|
|
ktype: "string",
|
|
count: 0,
|
|
err: nil,
|
|
},
|
|
{
|
|
cmd: "scan 15 match k2* count 5 type string",
|
|
cursor: 15,
|
|
match: "k2*",
|
|
ktype: "string",
|
|
count: 5,
|
|
err: nil,
|
|
},
|
|
{
|
|
cmd: "scan ten",
|
|
cursor: 0,
|
|
match: "",
|
|
count: 0,
|
|
err: redis.ErrInvalidInt,
|
|
},
|
|
{
|
|
cmd: "scan 15 *",
|
|
cursor: 0,
|
|
match: "",
|
|
count: 0,
|
|
err: redis.ErrSyntaxError,
|
|
},
|
|
{
|
|
cmd: "scan 15 * 5",
|
|
cursor: 0,
|
|
match: "",
|
|
count: 0,
|
|
err: redis.ErrSyntaxError,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.cmd, func(t *testing.T) {
|
|
cmd, err := redis.Parse(ParseScan, test.cmd)
|
|
be.Equal(t, err, test.err)
|
|
if err == nil {
|
|
be.Equal(t, cmd.cursor, test.cursor)
|
|
be.Equal(t, cmd.match, test.match)
|
|
be.Equal(t, cmd.ktype, test.ktype)
|
|
be.Equal(t, cmd.count, test.count)
|
|
} else {
|
|
be.Equal(t, cmd, Scan{})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestScanExec(t *testing.T) {
|
|
t.Run("scan all", func(t *testing.T) {
|
|
red := getRedka(t)
|
|
|
|
_ = red.Str().Set("k11", "11")
|
|
_ = red.Str().Set("k12", "12")
|
|
_ = red.Str().Set("k21", "21")
|
|
_ = red.Str().Set("k22", "22")
|
|
_ = red.Str().Set("k31", "31")
|
|
|
|
var cursor int
|
|
{
|
|
cmd := redis.MustParse(ParseScan, "scan 0")
|
|
conn := redis.NewFakeConn()
|
|
|
|
res, err := cmd.Run(conn, red)
|
|
be.Err(t, err, nil)
|
|
|
|
sres := res.(rkey.ScanResult)
|
|
be.True(t, sres.Cursor > 0)
|
|
be.Equal(t, len(sres.Keys), 5)
|
|
be.Equal(t, sres.Keys[0].Key, "k11")
|
|
be.Equal(t, sres.Keys[4].Key, "k31")
|
|
wantOut := fmt.Sprintf("2,%d,5,k11,k12,k21,k22,k31", sres.Cursor)
|
|
be.Equal(t, conn.Out(), wantOut)
|
|
cursor = sres.Cursor
|
|
}
|
|
{
|
|
next := fmt.Sprintf("scan %d", cursor)
|
|
cmd := redis.MustParse(ParseScan, next)
|
|
conn := redis.NewFakeConn()
|
|
|
|
res, err := cmd.Run(conn, red)
|
|
be.Err(t, err, nil)
|
|
|
|
sres := res.(rkey.ScanResult)
|
|
be.Equal(t, sres.Cursor, 0)
|
|
be.Equal(t, len(sres.Keys), 0)
|
|
be.Equal(t, conn.Out(), "2,0,0")
|
|
}
|
|
})
|
|
t.Run("scan pattern", func(t *testing.T) {
|
|
red := getRedka(t)
|
|
|
|
_ = red.Str().Set("k11", "11")
|
|
_ = red.Str().Set("k12", "12")
|
|
_ = red.Str().Set("k21", "21")
|
|
_ = red.Str().Set("k22", "22")
|
|
_ = red.Str().Set("k31", "31")
|
|
|
|
cmd := redis.MustParse(ParseScan, "scan 0 match k2*")
|
|
conn := redis.NewFakeConn()
|
|
|
|
res, err := cmd.Run(conn, red)
|
|
be.Err(t, err, nil)
|
|
|
|
sres := res.(rkey.ScanResult)
|
|
be.True(t, sres.Cursor > 0)
|
|
be.Equal(t, len(sres.Keys), 2)
|
|
be.Equal(t, sres.Keys[0].Key, "k21")
|
|
be.Equal(t, sres.Keys[1].Key, "k22")
|
|
wantOut := fmt.Sprintf("2,%d,2,k21,k22", sres.Cursor)
|
|
be.Equal(t, conn.Out(), wantOut)
|
|
})
|
|
t.Run("scan type", func(t *testing.T) {
|
|
red := getRedka(t)
|
|
|
|
_ = red.Str().Set("t1", "str")
|
|
_, _ = red.List().PushBack("t2", "elem")
|
|
_, _ = red.Hash().Set("t4", "field", "value")
|
|
_, _ = red.ZSet().Add("t5", "elem", 11)
|
|
|
|
cmd := redis.MustParse(ParseScan, "scan 0 match t* type hash")
|
|
conn := redis.NewFakeConn()
|
|
|
|
res, err := cmd.Run(conn, red)
|
|
be.Err(t, err, nil)
|
|
|
|
sres := res.(rkey.ScanResult)
|
|
be.True(t, sres.Cursor > 0)
|
|
be.Equal(t, len(sres.Keys), 1)
|
|
be.Equal(t, sres.Keys[0].Key, "t4")
|
|
wantOut := fmt.Sprintf("2,%d,1,t4", sres.Cursor)
|
|
be.Equal(t, conn.Out(), wantOut)
|
|
})
|
|
t.Run("scan count", func(t *testing.T) {
|
|
red := getRedka(t)
|
|
|
|
_ = red.Str().Set("k11", "11")
|
|
_ = red.Str().Set("k12", "12")
|
|
_ = red.Str().Set("k21", "21")
|
|
_ = red.Str().Set("k22", "22")
|
|
_ = red.Str().Set("k31", "31")
|
|
|
|
var cursor int
|
|
{
|
|
// page 1
|
|
cmd := redis.MustParse(ParseScan, "scan 0 match * count 2")
|
|
conn := redis.NewFakeConn()
|
|
|
|
res, err := cmd.Run(conn, red)
|
|
be.Err(t, err, nil)
|
|
|
|
sres := res.(rkey.ScanResult)
|
|
be.True(t, sres.Cursor > cursor)
|
|
be.Equal(t, len(sres.Keys), 2)
|
|
be.Equal(t, sres.Keys[0].Key, "k11")
|
|
be.Equal(t, sres.Keys[1].Key, "k12")
|
|
wantOut := fmt.Sprintf("2,%d,2,k11,k12", sres.Cursor)
|
|
be.Equal(t, conn.Out(), wantOut)
|
|
cursor = sres.Cursor
|
|
}
|
|
{
|
|
// page 2
|
|
next := fmt.Sprintf("scan %d match * count 2", cursor)
|
|
cmd := redis.MustParse(ParseScan, next)
|
|
conn := redis.NewFakeConn()
|
|
|
|
res, err := cmd.Run(conn, red)
|
|
be.Err(t, err, nil)
|
|
|
|
sres := res.(rkey.ScanResult)
|
|
be.True(t, sres.Cursor > cursor)
|
|
be.Equal(t, len(sres.Keys), 2)
|
|
be.Equal(t, sres.Keys[0].Key, "k21")
|
|
be.Equal(t, sres.Keys[1].Key, "k22")
|
|
wantOut := fmt.Sprintf("2,%d,2,k21,k22", sres.Cursor)
|
|
be.Equal(t, conn.Out(), wantOut)
|
|
cursor = sres.Cursor
|
|
}
|
|
{
|
|
// page 3
|
|
next := fmt.Sprintf("scan %d match * count 2", cursor)
|
|
cmd := redis.MustParse(ParseScan, next)
|
|
conn := redis.NewFakeConn()
|
|
|
|
res, err := cmd.Run(conn, red)
|
|
be.Err(t, err, nil)
|
|
|
|
sres := res.(rkey.ScanResult)
|
|
be.True(t, sres.Cursor > cursor)
|
|
be.Equal(t, len(sres.Keys), 1)
|
|
be.Equal(t, sres.Keys[0].Key, "k31")
|
|
wantOut := fmt.Sprintf("2,%d,1,k31", sres.Cursor)
|
|
be.Equal(t, conn.Out(), wantOut)
|
|
cursor = sres.Cursor
|
|
}
|
|
{
|
|
// no more pages
|
|
next := fmt.Sprintf("scan %d match * count 2", cursor)
|
|
cmd := redis.MustParse(ParseScan, next)
|
|
conn := redis.NewFakeConn()
|
|
|
|
res, err := cmd.Run(conn, red)
|
|
be.Err(t, err, nil)
|
|
|
|
sres := res.(rkey.ScanResult)
|
|
be.Equal(t, sres.Cursor, 0)
|
|
be.Equal(t, len(sres.Keys), 0)
|
|
be.Equal(t, conn.Out(), "2,0,0")
|
|
}
|
|
})
|
|
}
|