Better FLUSHDB/EXPIRES tests

This commit is contained in:
tidwall 2022-09-23 11:40:48 -07:00
parent 960c860b3a
commit d7ad01e593
3 changed files with 91 additions and 23 deletions

View File

@ -527,14 +527,20 @@ func (s *Server) cmdRENAME(msg *Message) (resp.Value, commandDetails, error) {
return res, d, nil
}
func (s *Server) cmdFLUSHDB(msg *Message) (res resp.Value, d commandDetails, err error) {
// FLUSHDB
func (s *Server) cmdFLUSHDB(msg *Message) (resp.Value, commandDetails, error) {
start := time.Now()
vs := msg.Args[1:]
if len(vs) != 0 {
err = errInvalidNumberOfArguments
return
// >> Args
args := msg.Args
if len(args) != 1 {
return retwerr(errInvalidNumberOfArguments)
}
// >> Operation
// clear the entire database
s.cols.Clear()
s.groupHooks.Clear()
@ -545,17 +551,21 @@ func (s *Server) cmdFLUSHDB(msg *Message) (res resp.Value, d commandDetails, err
s.hookTree.Clear()
s.hookCross.Clear()
// >> Response
var d commandDetails
d.command = "flushdb"
d.updated = true
d.timestamp = time.Now()
switch msg.OutputType {
case JSON:
var res resp.Value
if msg.OutputType == JSON {
res = resp.StringValue(`{"ok":true,"elapsed":"` +
time.Since(start).String() + "\"}")
case RESP:
} else {
res = resp.SimpleStringValue("OK")
}
return
return res, d, nil
}
// SET key id [FIELD name value ...] [EX seconds] [NX|XX]
@ -857,6 +867,9 @@ func (s *Server) cmdFSET(msg *Message) (resp.Value, commandDetails, error) {
// EXPIRE key id seconds
func (s *Server) cmdEXPIRE(msg *Message) (resp.Value, commandDetails, error) {
start := time.Now()
// >> Args
args := msg.Args
if len(args) != 4 {
return retwerr(errInvalidNumberOfArguments)
@ -866,12 +879,16 @@ func (s *Server) cmdEXPIRE(msg *Message) (resp.Value, commandDetails, error) {
if err != nil {
return retwerr(errInvalidArgument(svalue))
}
// >> Operation
var ok bool
var obj *object.Object
col, _ := s.cols.Get(key)
if col != nil {
// replace the expiration by getting the old objec
ex := time.Now().Add(time.Duration(float64(time.Second) * value)).UnixNano()
// replace the expiration by getting the old object
ex := time.Now().Add(
time.Duration(float64(time.Second) * value)).UnixNano()
o := col.Get(id)
ok = o != nil
if ok {
@ -879,6 +896,9 @@ func (s *Server) cmdEXPIRE(msg *Message) (resp.Value, commandDetails, error) {
col.Set(obj)
}
}
// >> Response
var d commandDetails
if ok {
d.key = key
@ -950,7 +970,8 @@ func (s *Server) cmdPERSIST(msg *Message) (resp.Value, commandDetails, error) {
switch msg.OutputType {
case JSON:
res = resp.SimpleStringValue(`{"ok":true,"elapsed":"` + time.Since(start).String() + "\"}")
res = resp.SimpleStringValue(`{"ok":true,"elapsed":"` +
time.Since(start).String() + "\"}")
case RESP:
if cleared {
res = resp.IntegerValue(1)

View File

@ -31,6 +31,7 @@ func subTestKeys(t *testing.T, mc *mockServer) {
runStep(t, mc, "WHEREIN", keys_WHEREIN_test)
runStep(t, mc, "WHEREEVAL", keys_WHEREEVAL_test)
runStep(t, mc, "TYPE", keys_TYPE_test)
runStep(t, mc, "FLUSHDB", keys_FLUSHDB_test)
}
func keys_BOUNDS_test(mc *mockServer) error {
@ -137,14 +138,26 @@ func keys_RENAMENX_test(mc *mockServer) error {
)
}
func keys_EXPIRE_test(mc *mockServer) error {
return mc.DoBatch([][]interface{}{
{"SET", "mykey", "myid", "STRING", "value"}, {"OK"},
{"EXPIRE", "mykey", "myid", 1}, {1},
{time.Second / 4}, {}, // sleep
{"GET", "mykey", "myid"}, {"value"},
{time.Second}, {}, // sleep
{"GET", "mykey", "myid"}, {nil},
})
return mc.DoBatch(
Do("SET", "mykey", "myid", "STRING", "value").OK(),
Do("EXPIRE", "mykey", "myid").Err("wrong number of arguments for 'expire' command"),
Do("EXPIRE", "mykey", "myid", "y").Err("invalid argument 'y'"),
Do("EXPIRE", "mykey", "myid", 1).Str("1"),
Do("EXPIRE", "mykey", "myid", 1).JSON().OK(),
Sleep(time.Second/4),
Do("GET", "mykey", "myid").Str("value"),
Sleep(time.Second),
Do("GET", "mykey", "myid").Str("<nil>"),
Do("EXPIRE", "mykey", "myid", 1).JSON().Err("key not found"),
Do("SET", "mykey", "myid1", "STRING", "value1").OK(),
Do("SET", "mykey", "myid2", "STRING", "value2").OK(),
Do("EXPIRE", "mykey", "myid1", 1).Str("1"),
Sleep(time.Second/4),
Do("GET", "mykey", "myid1").Str("value1"),
Sleep(time.Second),
Do("EXPIRE", "mykey", "myid1", 1).Str("0"),
Do("EXPIRE", "mykey", "myid1", 1).JSON().Err("id not found"),
)
}
func keys_FSET_test(mc *mockServer) error {
return mc.DoBatch([][]interface{}{
@ -435,3 +448,26 @@ func keys_TYPE_test(mc *mockServer) error {
Do("TYPE", "mykey").JSON().Str(`{"ok":true,"type":"hash"}`),
)
}
func keys_FLUSHDB_test(mc *mockServer) error {
return mc.DoBatch(
Do("SET", "mykey1", "myid1", "POINT", 33, -115).OK(),
Do("SET", "mykey2", "myid1", "POINT", 33, -115).OK(),
Do("SETCHAN", "mychan", "INTERSECTS", "mykey1", "BOUNDS", 10, 10, 10, 10).Str("1"),
Do("KEYS", "*").Str("[mykey1 mykey2]"),
Do("CHANS", "*").JSON().Custom(func(s string) error {
if gjson.Get(s, "chans.#").Int() != 1 {
return fmt.Errorf("expected '%d', got '%d'", 1, gjson.Get(s, "chans.#").Int())
}
return nil
}),
Do("FLUSHDB", "arg2").Err("wrong number of arguments for 'flushdb' command"),
Do("FLUSHDB").OK(),
Do("KEYS", "*").Str("[]"),
Do("CHANS", "*").Str("[]"),
Do("SET", "mykey1", "myid1", "POINT", 33, -115).OK(),
Do("SET", "mykey2", "myid1", "POINT", 33, -115).OK(),
Do("SETCHAN", "mychan", "INTERSECTS", "mykey1", "BOUNDS", 10, 10, 10, 10).Str("1"),
Do("FLUSHDB").JSON().OK(),
)
}

View File

@ -10,14 +10,17 @@ import (
"path/filepath"
"runtime"
"strings"
"time"
"github.com/tidwall/gjson"
)
type IO struct {
args []any
json bool
out any
args []any
json bool
out any
sleep bool
dur time.Duration
}
func Do(args ...any) *IO {
@ -76,6 +79,10 @@ func (cmd *IO) Err(msg string) *IO {
})
}
func Sleep(duration time.Duration) *IO {
return &IO{sleep: true, dur: duration}
}
type ioVisitor struct {
fset *token.FileSet
ln int
@ -222,6 +229,10 @@ func (cmd *IO) deepError(index int, err error) error {
}
func (mc *mockServer) doIOTest(index int, cmd *IO) error {
if cmd.sleep {
time.Sleep(cmd.dur)
return nil
}
// switch json mode if desired
if cmd.json {
if !mc.ioJSON {