Better RENAME/RENAMENX tests

This commit is contained in:
tidwall 2022-09-23 11:18:01 -07:00
parent ede1ce0269
commit 960c860b3a
4 changed files with 103 additions and 74 deletions

View File

@ -244,10 +244,11 @@ func (s *Server) cmdGET(msg *Message) (resp.Value, error) {
if i > 0 {
buf.WriteString(`,`)
}
buf.WriteString(jsonString(f.Name()) + ":" + f.Value().JSON())
buf.WriteString(jsonString(f.Name()) + ":" +
f.Value().JSON())
} else {
fvals = append(fvals,
resp.StringValue(f.Name()), resp.StringValue(f.Value().Data()))
fvals = append(fvals, resp.StringValue(f.Name()),
resp.StringValue(f.Value().Data()))
}
i++
return true
@ -441,7 +442,8 @@ func (s *Server) cmdDROP(msg *Message) (resp.Value, commandDetails, error) {
d.timestamp = time.Now()
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:
if d.updated {
res = resp.IntegerValue(1)
@ -452,54 +454,67 @@ func (s *Server) cmdDROP(msg *Message) (resp.Value, commandDetails, error) {
return res, d, nil
}
func (s *Server) cmdRename(msg *Message) (res resp.Value, d commandDetails, err error) {
nx := msg.Command() == "renamenx"
// RENAME key newkey
// RENAMENX key newkey
func (s *Server) cmdRENAME(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
// >> Args
args := msg.Args
if len(args) != 3 {
return retwerr(errInvalidNumberOfArguments)
}
if vs, d.newKey, ok = tokenval(vs); !ok || d.newKey == "" {
err = errInvalidNumberOfArguments
return
}
if len(vs) != 0 {
err = errInvalidNumberOfArguments
return
}
col, _ := s.cols.Get(d.key)
nx := strings.ToLower(args[0]) == "renamenx"
key := args[1]
newKey := args[2]
// >> Operation
col, _ := s.cols.Get(key)
if col == nil {
err = errKeyNotFound
return
return retwerr(errKeyNotFound)
}
var ierr error
s.hooks.Ascend(nil, func(v interface{}) bool {
h := v.(*Hook)
if h.Key == d.key || h.Key == d.newKey {
err = errKeyHasHooksSet
if h.Key == key || h.Key == newKey {
ierr = errKeyHasHooksSet
return false
}
return true
})
d.command = "rename"
newCol, _ := s.cols.Get(d.newKey)
if ierr != nil {
return retwerr(ierr)
}
var updated bool
newCol, _ := s.cols.Get(newKey)
if newCol == nil {
d.updated = true
} else if nx {
d.updated = false
} else {
s.cols.Delete(d.newKey)
d.updated = true
updated = true
} else if !nx {
s.cols.Delete(newKey)
updated = true
}
if d.updated {
s.cols.Delete(d.key)
s.cols.Set(d.newKey, col)
if updated {
s.cols.Delete(key)
s.cols.Set(newKey, col)
}
// >> Response
var d commandDetails
var res resp.Value
d.command = "rename"
d.key = key
d.newKey = newKey
d.updated = updated
d.timestamp = time.Now()
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:
if !nx {
res = resp.SimpleStringValue("OK")
@ -509,7 +524,7 @@ func (s *Server) cmdRename(msg *Message) (res resp.Value, d commandDetails, err
res = resp.IntegerValue(0)
}
}
return
return res, d, nil
}
func (s *Server) cmdFLUSHDB(msg *Message) (res resp.Value, d commandDetails, err error) {
@ -535,7 +550,8 @@ func (s *Server) cmdFLUSHDB(msg *Message) (res resp.Value, d commandDetails, err
d.timestamp = time.Now()
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:
res = resp.SimpleStringValue("OK")
}
@ -543,7 +559,8 @@ func (s *Server) cmdFLUSHDB(msg *Message) (res resp.Value, d commandDetails, err
}
// SET key id [FIELD name value ...] [EX seconds] [NX|XX]
// (OBJECT geojson)|(POINT lat lon z)|(BOUNDS minlat minlon maxlat maxlon)|(HASH geohash)|(STRING value)
// (OBJECT geojson)|(POINT lat lon z)|(BOUNDS minlat minlon maxlat maxlon)|
// (HASH geohash)|(STRING value)
func (s *Server) cmdSET(msg *Message) (resp.Value, commandDetails, error) {
start := time.Now()
if s.config.maxMemory() > 0 && s.outOfMemory.on() {

View File

@ -604,9 +604,9 @@ func (s *Server) commandInScript(msg *Message) (
case "expire":
res, d, err = s.cmdEXPIRE(msg)
case "rename":
res, d, err = s.cmdRename(msg)
res, d, err = s.cmdRENAME(msg)
case "renamenx":
res, d, err = s.cmdRename(msg)
res, d, err = s.cmdRENAME(msg)
case "persist":
res, d, err = s.cmdPERSIST(msg)
case "ttl":

View File

@ -1028,9 +1028,9 @@ func (s *Server) command(msg *Message, client *Client) (
case "flushdb":
res, d, err = s.cmdFLUSHDB(msg)
case "rename":
res, d, err = s.cmdRename(msg)
res, d, err = s.cmdRENAME(msg)
case "renamenx":
res, d, err = s.cmdRename(msg)
res, d, err = s.cmdRENAME(msg)
case "sethook":
res, d, err = s.cmdSetHook(msg)
case "delhook":

View File

@ -85,44 +85,56 @@ func keys_DROP_test(mc *mockServer) error {
Do("SCAN", "mykey", "COUNT").Str("0"),
Do("DROP", "mykey").Str("0"),
Do("SCAN", "mykey", "COUNT").Str("0"),
Do("SET", "mykey", "myid1", "HASH", "9my5xp7").Str("OK"),
Do("SET", "mykey", "myid1", "HASH", "9my5xp7").OK(),
Do("DROP", "mykey").JSON().OK(),
Do("DROP", "mykey").JSON().OK(),
)
}
func keys_RENAME_test(mc *mockServer) error {
return mc.DoBatch([][]interface{}{
{"SET", "mykey", "myid1", "HASH", "9my5xp7"}, {"OK"},
{"SET", "mykey", "myid2", "HASH", "9my5xp8"}, {"OK"},
{"SCAN", "mykey", "COUNT"}, {2},
{"RENAME", "mykey", "mynewkey"}, {"OK"},
{"SCAN", "mykey", "COUNT"}, {0},
{"SCAN", "mynewkey", "COUNT"}, {2},
{"SET", "mykey", "myid3", "HASH", "9my5xp7"}, {"OK"},
{"RENAME", "mykey", "mynewkey"}, {"OK"},
{"SCAN", "mykey", "COUNT"}, {0},
{"SCAN", "mynewkey", "COUNT"}, {1},
{"RENAME", "foo", "mynewkey"}, {"ERR key not found"},
{"SCAN", "mynewkey", "COUNT"}, {1},
})
return mc.DoBatch(
Do("SET", "mykey", "myid1", "HASH", "9my5xp7").OK(),
Do("SET", "mykey", "myid2", "HASH", "9my5xp8").OK(),
Do("SCAN", "mykey", "COUNT").Str("2"),
Do("RENAME", "foo", "mynewkey", "arg3").Err("wrong number of arguments for 'rename' command"),
Do("RENAME", "mykey", "mynewkey").OK(),
Do("SCAN", "mykey", "COUNT").Str("0"),
Do("SCAN", "mynewkey", "COUNT").Str("2"),
Do("SET", "mykey", "myid3", "HASH", "9my5xp7").OK(),
Do("RENAME", "mykey", "mynewkey").OK(),
Do("SCAN", "mykey", "COUNT").Str("0"),
Do("SCAN", "mynewkey", "COUNT").Str("1"),
Do("RENAME", "foo", "mynewkey").Err("key not found"),
Do("SCAN", "mynewkey", "COUNT").Str("1"),
Do("SETCHAN", "mychan", "INTERSECTS", "mynewkey", "BOUNDS", 10, 10, 20, 20).Str("1"),
Do("RENAME", "mynewkey", "foo2").Err("key has hooks set"),
Do("RENAMENX", "mynewkey", "foo2").Err("key has hooks set"),
Do("SET", "mykey", "myid1", "HASH", "9my5xp7").OK(),
Do("RENAME", "mykey", "foo2").OK(),
Do("RENAMENX", "foo2", "foo3").Str("1"),
Do("RENAMENX", "foo2", "foo3").Err("key not found"),
Do("RENAME", "foo2", "foo3").JSON().Err("key not found"),
Do("SET", "mykey", "myid1", "HASH", "9my5xp7").OK(),
Do("RENAMENX", "mykey", "foo3").Str("0"),
Do("RENAME", "foo3", "foo4").JSON().OK(),
)
}
func keys_RENAMENX_test(mc *mockServer) error {
return mc.DoBatch([][]interface{}{
{"SET", "mykey", "myid1", "HASH", "9my5xp7"}, {"OK"},
{"SET", "mykey", "myid2", "HASH", "9my5xp8"}, {"OK"},
{"SCAN", "mykey", "COUNT"}, {2},
{"RENAMENX", "mykey", "mynewkey"}, {1},
{"SCAN", "mykey", "COUNT"}, {0},
{"DROP", "mykey"}, {0},
{"SCAN", "mykey", "COUNT"}, {0},
{"SCAN", "mynewkey", "COUNT"}, {2},
{"SET", "mykey", "myid3", "HASH", "9my5xp7"}, {"OK"},
{"RENAMENX", "mykey", "mynewkey"}, {0},
{"SCAN", "mykey", "COUNT"}, {1},
{"SCAN", "mynewkey", "COUNT"}, {2},
{"RENAMENX", "foo", "mynewkey"}, {"ERR key not found"},
{"SCAN", "mynewkey", "COUNT"}, {2},
})
return mc.DoBatch(
Do("SET", "mykey", "myid1", "HASH", "9my5xp7").OK(),
Do("SET", "mykey", "myid2", "HASH", "9my5xp8").OK(),
Do("SCAN", "mykey", "COUNT").Str("2"),
Do("RENAMENX", "mykey", "mynewkey").Str("1"),
Do("SCAN", "mykey", "COUNT").Str("0"),
Do("DROP", "mykey").Str("0"),
Do("SCAN", "mykey", "COUNT").Str("0"),
Do("SCAN", "mynewkey", "COUNT").Str("2"),
Do("SET", "mykey", "myid3", "HASH", "9my5xp7").OK(),
Do("RENAMENX", "mykey", "mynewkey").Str("0"),
Do("SCAN", "mykey", "COUNT").Str("1"),
Do("SCAN", "mynewkey", "COUNT").Str("2"),
Do("RENAMENX", "foo", "mynewkey").Str("ERR key not found"),
Do("SCAN", "mynewkey", "COUNT").Str("2"),
)
}
func keys_EXPIRE_test(mc *mockServer) error {
return mc.DoBatch([][]interface{}{