mirror of https://github.com/tidwall/tile38.git
Better DEL/PDEL/TYPE tests
This commit is contained in:
parent
ef95f04aca
commit
db380a4fee
|
@ -73,33 +73,38 @@ func (s *Server) cmdBOUNDS(msg *Message) (resp.Value, error) {
|
|||
return vals[0], nil
|
||||
}
|
||||
|
||||
func (s *Server) cmdType(msg *Message) (resp.Value, error) {
|
||||
// TYPE key
|
||||
// undocumented return "none" or "hash"
|
||||
func (s *Server) cmdTYPE(msg *Message) (resp.Value, error) {
|
||||
start := time.Now()
|
||||
vs := msg.Args[1:]
|
||||
|
||||
var ok bool
|
||||
var key string
|
||||
if _, key, ok = tokenval(vs); !ok || key == "" {
|
||||
return NOMessage, errInvalidNumberOfArguments
|
||||
// >> Args
|
||||
|
||||
args := msg.Args
|
||||
if len(args) != 2 {
|
||||
return retrerr(errInvalidNumberOfArguments)
|
||||
}
|
||||
key := args[1]
|
||||
|
||||
// >> Operation
|
||||
|
||||
col, _ := s.cols.Get(key)
|
||||
if col == nil {
|
||||
if msg.OutputType == RESP {
|
||||
return resp.SimpleStringValue("none"), nil
|
||||
}
|
||||
return NOMessage, errKeyNotFound
|
||||
return retrerr(errKeyNotFound)
|
||||
}
|
||||
|
||||
// >> Response
|
||||
|
||||
typ := "hash"
|
||||
|
||||
switch msg.OutputType {
|
||||
case JSON:
|
||||
return resp.StringValue(`{"ok":true,"type":` + string(typ) + `,"elapsed":"` + time.Since(start).String() + "\"}"), nil
|
||||
case RESP:
|
||||
return resp.SimpleStringValue(typ), nil
|
||||
if msg.OutputType == JSON {
|
||||
return resp.StringValue(`{"ok":true,"type":` + jsonString(typ) +
|
||||
`,"elapsed":"` + time.Since(start).String() + "\"}"), nil
|
||||
}
|
||||
return NOMessage, nil
|
||||
return resp.SimpleStringValue(typ), nil
|
||||
}
|
||||
|
||||
func (s *Server) cmdGet(msg *Message) (resp.Value, error) {
|
||||
|
@ -262,7 +267,7 @@ func (s *Server) cmdGet(msg *Message) (resp.Value, error) {
|
|||
}
|
||||
|
||||
// DEL key id [ERRON404]
|
||||
func (s *Server) cmdDel(msg *Message) (resp.Value, commandDetails, error) {
|
||||
func (s *Server) cmdDEL(msg *Message) (resp.Value, commandDetails, error) {
|
||||
start := time.Now()
|
||||
|
||||
// >> Args
|
||||
|
@ -329,85 +334,75 @@ func (s *Server) cmdDel(msg *Message) (resp.Value, commandDetails, error) {
|
|||
return res, d, nil
|
||||
}
|
||||
|
||||
func (s *Server) cmdPdel(msg *Message) (res resp.Value, d commandDetails, err error) {
|
||||
// PDEL key pattern
|
||||
func (s *Server) cmdPDEL(msg *Message) (resp.Value, commandDetails, error) {
|
||||
start := time.Now()
|
||||
vs := msg.Args[1:]
|
||||
var ok bool
|
||||
if vs, d.key, ok = tokenval(vs); !ok || d.key == "" {
|
||||
err = errInvalidNumberOfArguments
|
||||
return
|
||||
}
|
||||
if vs, d.pattern, ok = tokenval(vs); !ok || d.pattern == "" {
|
||||
err = errInvalidNumberOfArguments
|
||||
return
|
||||
}
|
||||
if len(vs) != 0 {
|
||||
err = errInvalidNumberOfArguments
|
||||
return
|
||||
}
|
||||
now := time.Now()
|
||||
iter := func(o *object.Object) bool {
|
||||
if match, _ := glob.Match(d.pattern, o.ID()); match {
|
||||
d.children = append(d.children, &commandDetails{
|
||||
command: "del",
|
||||
updated: true,
|
||||
timestamp: now,
|
||||
key: d.key,
|
||||
obj: o,
|
||||
})
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var expired int
|
||||
col, _ := s.cols.Get(d.key)
|
||||
// >> Args
|
||||
|
||||
args := msg.Args
|
||||
if len(args) != 3 {
|
||||
return retwerr(errInvalidNumberOfArguments)
|
||||
}
|
||||
key := args[1]
|
||||
pattern := args[2]
|
||||
|
||||
// >> Operation
|
||||
|
||||
now := time.Now()
|
||||
var children []*commandDetails
|
||||
col, _ := s.cols.Get(key)
|
||||
if col != nil {
|
||||
g := glob.Parse(d.pattern, false)
|
||||
g := glob.Parse(pattern, false)
|
||||
var ids []string
|
||||
iter := func(o *object.Object) bool {
|
||||
if match, _ := glob.Match(pattern, o.ID()); match {
|
||||
ids = append(ids, o.ID())
|
||||
}
|
||||
return true
|
||||
}
|
||||
if g.Limits[0] == "" && g.Limits[1] == "" {
|
||||
col.Scan(false, nil, msg.Deadline, iter)
|
||||
} else {
|
||||
col.ScanRange(g.Limits[0], g.Limits[1], false, nil, msg.Deadline, iter)
|
||||
col.ScanRange(g.Limits[0], g.Limits[1],
|
||||
false, nil, msg.Deadline, iter)
|
||||
}
|
||||
var atLeastOneNotDeleted bool
|
||||
for i, dc := range d.children {
|
||||
old := col.Delete(dc.obj.ID())
|
||||
if old == nil {
|
||||
d.children[i].command = "?"
|
||||
atLeastOneNotDeleted = true
|
||||
} else {
|
||||
dc.obj = old
|
||||
d.children[i] = dc
|
||||
}
|
||||
s.groupDisconnectObject(dc.key, dc.obj.ID())
|
||||
}
|
||||
if atLeastOneNotDeleted {
|
||||
var nchildren []*commandDetails
|
||||
for _, dc := range d.children {
|
||||
if dc.command == "del" {
|
||||
nchildren = append(nchildren, dc)
|
||||
}
|
||||
}
|
||||
d.children = nchildren
|
||||
for _, id := range ids {
|
||||
obj := col.Delete(id)
|
||||
children = append(children, &commandDetails{
|
||||
command: "del",
|
||||
updated: true,
|
||||
timestamp: now,
|
||||
key: key,
|
||||
obj: obj,
|
||||
})
|
||||
s.groupDisconnectObject(key, id)
|
||||
}
|
||||
if col.Count() == 0 {
|
||||
s.cols.Delete(d.key)
|
||||
s.cols.Delete(key)
|
||||
}
|
||||
}
|
||||
|
||||
// >> Response
|
||||
|
||||
var d commandDetails
|
||||
var res resp.Value
|
||||
|
||||
d.command = "pdel"
|
||||
d.children = children
|
||||
d.key = key
|
||||
d.pattern = pattern
|
||||
d.updated = len(d.children) > 0
|
||||
d.timestamp = now
|
||||
d.parent = true
|
||||
switch msg.OutputType {
|
||||
case JSON:
|
||||
res = resp.StringValue(`{"ok":true,"elapsed":"` + time.Since(start).String() + "\"}")
|
||||
res = resp.StringValue(`{"ok":true,"elapsed":"` +
|
||||
time.Since(start).String() + "\"}")
|
||||
case RESP:
|
||||
total := len(d.children) - expired
|
||||
if total < 0 {
|
||||
total = 0
|
||||
}
|
||||
res = resp.IntegerValue(total)
|
||||
res = resp.IntegerValue(len(d.children))
|
||||
}
|
||||
return
|
||||
return res, d, nil
|
||||
}
|
||||
|
||||
func (s *Server) cmdDrop(msg *Message) (res resp.Value, d commandDetails, err error) {
|
||||
|
|
|
@ -42,7 +42,7 @@ func (s *Server) backgroundExpireObjects(now time.Time) {
|
|||
return true
|
||||
})
|
||||
for _, msg := range msgs {
|
||||
_, d, err := s.cmdDel(msg)
|
||||
_, d, err := s.cmdDEL(msg)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -596,9 +596,9 @@ func (s *Server) commandInScript(msg *Message) (
|
|||
case "fset":
|
||||
res, d, err = s.cmdFSET(msg)
|
||||
case "del":
|
||||
res, d, err = s.cmdDel(msg)
|
||||
res, d, err = s.cmdDEL(msg)
|
||||
case "pdel":
|
||||
res, d, err = s.cmdPdel(msg)
|
||||
res, d, err = s.cmdPDEL(msg)
|
||||
case "drop":
|
||||
res, d, err = s.cmdDrop(msg)
|
||||
case "expire":
|
||||
|
@ -634,7 +634,7 @@ func (s *Server) commandInScript(msg *Message) (
|
|||
case "jdel":
|
||||
res, d, err = s.cmdJdel(msg)
|
||||
case "type":
|
||||
res, err = s.cmdType(msg)
|
||||
res, err = s.cmdTYPE(msg)
|
||||
case "keys":
|
||||
res, err = s.cmdKeys(msg)
|
||||
case "test":
|
||||
|
|
|
@ -1020,9 +1020,9 @@ func (s *Server) command(msg *Message, client *Client) (
|
|||
case "fset":
|
||||
res, d, err = s.cmdFSET(msg)
|
||||
case "del":
|
||||
res, d, err = s.cmdDel(msg)
|
||||
res, d, err = s.cmdDEL(msg)
|
||||
case "pdel":
|
||||
res, d, err = s.cmdPdel(msg)
|
||||
res, d, err = s.cmdPDEL(msg)
|
||||
case "drop":
|
||||
res, d, err = s.cmdDrop(msg)
|
||||
case "flushdb":
|
||||
|
@ -1106,7 +1106,7 @@ func (s *Server) command(msg *Message, client *Client) (
|
|||
case "jdel":
|
||||
res, d, err = s.cmdJdel(msg)
|
||||
case "type":
|
||||
res, err = s.cmdType(msg)
|
||||
res, err = s.cmdTYPE(msg)
|
||||
case "keys":
|
||||
res, err = s.cmdKeys(msg)
|
||||
case "output":
|
||||
|
|
|
@ -11,4 +11,6 @@ go tool cover -html=/tmp/coverage.out -o /tmp/coverage.html
|
|||
echo "details: file:///tmp/coverage.html"
|
||||
cd ..
|
||||
|
||||
go test $(go list ./... | grep -v /vendor/ | grep -v /tests)
|
||||
if [[ "$GOTEST" == "" ]]; then
|
||||
go test $(go list ./... | grep -v /vendor/ | grep -v /tests)
|
||||
fi
|
||||
|
|
|
@ -30,38 +30,50 @@ func subTestKeys(t *testing.T, mc *mockServer) {
|
|||
runStep(t, mc, "FIELDS", keys_FIELDS_test)
|
||||
runStep(t, mc, "WHEREIN", keys_WHEREIN_test)
|
||||
runStep(t, mc, "WHEREEVAL", keys_WHEREEVAL_test)
|
||||
runStep(t, mc, "TYPE", keys_TYPE_test)
|
||||
}
|
||||
|
||||
func keys_BOUNDS_test(mc *mockServer) error {
|
||||
return mc.DoBatch(
|
||||
Do("BOUNDS", "mykey").String("<nil>"),
|
||||
Do("BOUNDS", "mykey").JSON().Error("key not found"),
|
||||
Do("BOUNDS", "mykey").Str("<nil>"),
|
||||
Do("BOUNDS", "mykey").JSON().Err("key not found"),
|
||||
Do("SET", "mykey", "myid1", "POINT", 33, -115).OK(),
|
||||
Do("BOUNDS", "mykey").String("[[-115 33] [-115 33]]"),
|
||||
Do("BOUNDS", "mykey").JSON().String(`{"ok":true,"bounds":{"type":"Point","coordinates":[-115,33]}}`),
|
||||
Do("BOUNDS", "mykey").Str("[[-115 33] [-115 33]]"),
|
||||
Do("BOUNDS", "mykey").JSON().Str(`{"ok":true,"bounds":{"type":"Point","coordinates":[-115,33]}}`),
|
||||
Do("SET", "mykey", "myid2", "POINT", 34, -112).OK(),
|
||||
Do("BOUNDS", "mykey").String("[[-115 33] [-112 34]]"),
|
||||
Do("DEL", "mykey", "myid2").String("1"),
|
||||
Do("BOUNDS", "mykey").String("[[-115 33] [-115 33]]"),
|
||||
Do("BOUNDS", "mykey").Str("[[-115 33] [-112 34]]"),
|
||||
Do("DEL", "mykey", "myid2").Str("1"),
|
||||
Do("BOUNDS", "mykey").Str("[[-115 33] [-115 33]]"),
|
||||
Do("SET", "mykey", "myid3", "OBJECT", `{"type":"Point","coordinates":[-130,38,10]}`).OK(),
|
||||
Do("SET", "mykey", "myid4", "OBJECT", `{"type":"Point","coordinates":[-110,25,-8]}`).OK(),
|
||||
Do("BOUNDS", "mykey").String("[[-130 25] [-110 38]]"),
|
||||
Do("BOUNDS", "mykey", "hello").Error("wrong number of arguments for 'bounds' command"),
|
||||
Do("BOUNDS", "nada").String("<nil>"),
|
||||
Do("BOUNDS", "nada").JSON().Error("key not found"),
|
||||
Do("BOUNDS", "").String("<nil>"),
|
||||
Do("BOUNDS", "mykey").JSON().String(`{"ok":true,"bounds":{"type":"Polygon","coordinates":[[[-130,25],[-110,25],[-110,38],[-130,38],[-130,25]]]}}`),
|
||||
Do("BOUNDS", "mykey").Str("[[-130 25] [-110 38]]"),
|
||||
Do("BOUNDS", "mykey", "hello").Err("wrong number of arguments for 'bounds' command"),
|
||||
Do("BOUNDS", "nada").Str("<nil>"),
|
||||
Do("BOUNDS", "nada").JSON().Err("key not found"),
|
||||
Do("BOUNDS", "").Str("<nil>"),
|
||||
Do("BOUNDS", "mykey").JSON().Str(`{"ok":true,"bounds":{"type":"Polygon","coordinates":[[[-130,25],[-110,25],[-110,38],[-130,38],[-130,25]]]}}`),
|
||||
)
|
||||
}
|
||||
|
||||
func keys_DEL_test(mc *mockServer) error {
|
||||
return mc.DoBatch([][]interface{}{
|
||||
{"SET", "mykey", "myid", "POINT", 33, -115}, {"OK"},
|
||||
{"GET", "mykey", "myid", "POINT"}, {"[33 -115]"},
|
||||
{"DEL", "mykey", "myid"}, {"1"},
|
||||
{"GET", "mykey", "myid"}, {nil},
|
||||
})
|
||||
return mc.DoBatch(
|
||||
Do("SET", "mykey", "myid", "POINT", 33, -115).OK(),
|
||||
Do("GET", "mykey", "myid", "POINT").Str("[33 -115]"),
|
||||
Do("DEL", "mykey", "myid2", "ERRON404").Err("id not found"),
|
||||
Do("DEL", "mykey", "myid").Str("1"),
|
||||
Do("DEL", "mykey", "myid").Str("0"),
|
||||
Do("DEL", "mykey").Err("wrong number of arguments for 'del' command"),
|
||||
Do("GET", "mykey", "myid").Str("<nil>"),
|
||||
Do("DEL", "mykey", "myid", "ERRON404").Err("key not found"),
|
||||
Do("DEL", "mykey", "myid", "invalid-arg").Err("invalid argument 'invalid-arg'"),
|
||||
Do("SET", "mykey", "myid", "POINT", 33, -115).OK(),
|
||||
Do("DEL", "mykey", "myid2", "ERRON404").JSON().Err("id not found"),
|
||||
Do("DEL", "mykey", "myid").JSON().OK(),
|
||||
Do("DEL", "mykey", "myid").JSON().OK(),
|
||||
Do("DEL", "mykey", "myid", "ERRON404").JSON().Err("key not found"),
|
||||
)
|
||||
}
|
||||
|
||||
func keys_DROP_test(mc *mockServer) error {
|
||||
return mc.DoBatch([][]interface{}{
|
||||
{"SET", "mykey", "myid1", "HASH", "9my5xp7"}, {"OK"},
|
||||
|
@ -138,14 +150,14 @@ func keys_FSET_test(mc *mockServer) error {
|
|||
})
|
||||
}
|
||||
func keys_GET_test(mc *mockServer) error {
|
||||
return mc.DoBatch([][]interface{}{
|
||||
{"SET", "mykey", "myid", "STRING", "value"}, {"OK"},
|
||||
{"GET", "mykey", "myid"}, {"value"},
|
||||
{"SET", "mykey", "myid", "STRING", "value2"}, {"OK"},
|
||||
{"GET", "mykey", "myid"}, {"value2"},
|
||||
{"DEL", "mykey", "myid"}, {"1"},
|
||||
{"GET", "mykey", "myid"}, {nil},
|
||||
})
|
||||
return mc.DoBatch(
|
||||
Do("SET", "mykey", "myid", "STRING", "value").OK(),
|
||||
Do("GET", "mykey", "myid").Str("value"),
|
||||
Do("SET", "mykey", "myid", "STRING", "value2").OK(),
|
||||
Do("GET", "mykey", "myid").Str("value2"),
|
||||
Do("DEL", "mykey", "myid").Str("1"),
|
||||
Do("GET", "mykey", "myid").Str("<nil>"),
|
||||
)
|
||||
}
|
||||
func keys_KEYS_test(mc *mockServer) error {
|
||||
return mc.DoBatch([][]interface{}{
|
||||
|
@ -314,24 +326,31 @@ func keys_FIELDS_test(mc *mockServer) error {
|
|||
}
|
||||
|
||||
func keys_PDEL_test(mc *mockServer) error {
|
||||
return mc.DoBatch([][]interface{}{
|
||||
{"SET", "mykey", "myid1a", "POINT", 33, -115}, {"OK"},
|
||||
{"SET", "mykey", "myid1b", "POINT", 33, -115}, {"OK"},
|
||||
{"SET", "mykey", "myid2a", "POINT", 33, -115}, {"OK"},
|
||||
{"SET", "mykey", "myid2b", "POINT", 33, -115}, {"OK"},
|
||||
{"SET", "mykey", "myid3a", "POINT", 33, -115}, {"OK"},
|
||||
{"SET", "mykey", "myid3b", "POINT", 33, -115}, {"OK"},
|
||||
{"SET", "mykey", "myid4a", "POINT", 33, -115}, {"OK"},
|
||||
{"SET", "mykey", "myid4b", "POINT", 33, -115}, {"OK"},
|
||||
{"PDEL", "mykeyNA", "*"}, {0},
|
||||
{"PDEL", "mykey", "myid1a"}, {1},
|
||||
{"PDEL", "mykey", "myid1a"}, {0},
|
||||
{"PDEL", "mykey", "myid1*"}, {1},
|
||||
{"PDEL", "mykey", "myid2*"}, {2},
|
||||
{"PDEL", "mykey", "*b"}, {2},
|
||||
{"PDEL", "mykey", "*"}, {2},
|
||||
{"PDEL", "mykey", "*"}, {0},
|
||||
})
|
||||
return mc.DoBatch(
|
||||
Do("SET", "mykey", "myid1a", "POINT", 33, -115).OK(),
|
||||
Do("SET", "mykey", "myid1b", "POINT", 33, -115).OK(),
|
||||
Do("SET", "mykey", "myid2a", "POINT", 33, -115).OK(),
|
||||
Do("SET", "mykey", "myid2b", "POINT", 33, -115).OK(),
|
||||
Do("SET", "mykey", "myid3a", "POINT", 33, -115).OK(),
|
||||
Do("SET", "mykey", "myid3b", "POINT", 33, -115).OK(),
|
||||
Do("SET", "mykey", "myid4a", "POINT", 33, -115).OK(),
|
||||
Do("SET", "mykey", "myid4b", "POINT", 33, -115).OK(),
|
||||
Do("PDEL", "mykey").Err("wrong number of arguments for 'pdel' command"),
|
||||
Do("PDEL", "mykeyNA", "*").Str("0"),
|
||||
Do("PDEL", "mykey", "myid1a").Str("1"),
|
||||
Do("PDEL", "mykey", "myid1a").Str("0"),
|
||||
Do("PDEL", "mykey", "myid1*").Str("1"),
|
||||
Do("PDEL", "mykey", "myid2*").Str("2"),
|
||||
Do("PDEL", "mykey", "*b").Str("2"),
|
||||
Do("PDEL", "mykey", "*").Str("2"),
|
||||
Do("PDEL", "mykey", "*").Str("0"),
|
||||
Do("SET", "mykey", "myid1a", "POINT", 33, -115).OK(),
|
||||
Do("SET", "mykey", "myid1b", "POINT", 33, -115).OK(),
|
||||
Do("SET", "mykey", "myid2a", "POINT", 33, -115).OK(),
|
||||
Do("SET", "mykey", "myid2b", "POINT", 33, -115).OK(),
|
||||
Do("SET", "mykey", "myid3a", "POINT", 33, -115).OK(),
|
||||
Do("PDEL", "mykey", "*").JSON().OK(),
|
||||
)
|
||||
}
|
||||
|
||||
func keys_WHEREIN_test(mc *mockServer) error {
|
||||
|
@ -363,3 +382,14 @@ func keys_WHEREEVAL_test(mc *mockServer) error {
|
|||
{"WITHIN", "mykey", "WHEREEVAL", "return FIELDS.a > tonumber(ARGV[1]) and FIELDS.a ~= tonumber(ARGV[2])", 2, 0.5, 3, "BOUNDS", 32.8, -115.2, 33.2, -114.8}, {`[0 [[myid_a2 {"type":"Point","coordinates":[-115,32.99]} [a 2]] [myid_a1 {"type":"Point","coordinates":[-115,33]} [a 1]]]]`},
|
||||
})
|
||||
}
|
||||
|
||||
func keys_TYPE_test(mc *mockServer) error {
|
||||
return mc.DoBatch(
|
||||
Do("SET", "mykey", "myid1", "POINT", 33, -115).OK(),
|
||||
Do("TYPE", "mykey").Str("hash"),
|
||||
Do("TYPE", "mykey", "hello").Err("wrong number of arguments for 'type' command"),
|
||||
Do("TYPE", "mykey2").Str("none"),
|
||||
Do("TYPE", "mykey2").JSON().Err("key not found"),
|
||||
Do("TYPE", "mykey").JSON().Str(`{"ok":true,"type":"hash"}`),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ func (cmd *IO) JSON() *IO {
|
|||
cmd.json = true
|
||||
return cmd
|
||||
}
|
||||
func (cmd *IO) String(s string) *IO {
|
||||
func (cmd *IO) Str(s string) *IO {
|
||||
cmd.out = s
|
||||
return cmd
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ func (cmd *IO) OK() *IO {
|
|||
})
|
||||
}
|
||||
|
||||
func (cmd *IO) Error(msg string) *IO {
|
||||
func (cmd *IO) Err(msg string) *IO {
|
||||
return cmd.Custom(func(s string) error {
|
||||
if cmd.json {
|
||||
if gjson.Get(s, "ok").Type != gjson.False {
|
||||
|
|
Loading…
Reference in New Issue