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 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() start := time.Now()
vs := msg.Args[1:]
if len(vs) != 0 { // >> Args
err = errInvalidNumberOfArguments
return args := msg.Args
if len(args) != 1 {
return retwerr(errInvalidNumberOfArguments)
} }
// >> Operation
// clear the entire database // clear the entire database
s.cols.Clear() s.cols.Clear()
s.groupHooks.Clear() s.groupHooks.Clear()
@ -545,17 +551,21 @@ func (s *Server) cmdFLUSHDB(msg *Message) (res resp.Value, d commandDetails, err
s.hookTree.Clear() s.hookTree.Clear()
s.hookCross.Clear() s.hookCross.Clear()
// >> Response
var d commandDetails
d.command = "flushdb" d.command = "flushdb"
d.updated = true d.updated = true
d.timestamp = time.Now() d.timestamp = time.Now()
switch msg.OutputType {
case JSON: var res resp.Value
if msg.OutputType == JSON {
res = resp.StringValue(`{"ok":true,"elapsed":"` + res = resp.StringValue(`{"ok":true,"elapsed":"` +
time.Since(start).String() + "\"}") time.Since(start).String() + "\"}")
case RESP: } else {
res = resp.SimpleStringValue("OK") res = resp.SimpleStringValue("OK")
} }
return return res, d, nil
} }
// SET key id [FIELD name value ...] [EX seconds] [NX|XX] // 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 // EXPIRE key id seconds
func (s *Server) cmdEXPIRE(msg *Message) (resp.Value, commandDetails, error) { func (s *Server) cmdEXPIRE(msg *Message) (resp.Value, commandDetails, error) {
start := time.Now() start := time.Now()
// >> Args
args := msg.Args args := msg.Args
if len(args) != 4 { if len(args) != 4 {
return retwerr(errInvalidNumberOfArguments) return retwerr(errInvalidNumberOfArguments)
@ -866,12 +879,16 @@ func (s *Server) cmdEXPIRE(msg *Message) (resp.Value, commandDetails, error) {
if err != nil { if err != nil {
return retwerr(errInvalidArgument(svalue)) return retwerr(errInvalidArgument(svalue))
} }
// >> Operation
var ok bool var ok bool
var obj *object.Object var obj *object.Object
col, _ := s.cols.Get(key) col, _ := s.cols.Get(key)
if col != nil { if col != nil {
// replace the expiration by getting the old objec // replace the expiration by getting the old object
ex := time.Now().Add(time.Duration(float64(time.Second) * value)).UnixNano() ex := time.Now().Add(
time.Duration(float64(time.Second) * value)).UnixNano()
o := col.Get(id) o := col.Get(id)
ok = o != nil ok = o != nil
if ok { if ok {
@ -879,6 +896,9 @@ func (s *Server) cmdEXPIRE(msg *Message) (resp.Value, commandDetails, error) {
col.Set(obj) col.Set(obj)
} }
} }
// >> Response
var d commandDetails var d commandDetails
if ok { if ok {
d.key = key d.key = key
@ -950,7 +970,8 @@ func (s *Server) cmdPERSIST(msg *Message) (resp.Value, commandDetails, error) {
switch msg.OutputType { switch msg.OutputType {
case JSON: case JSON:
res = resp.SimpleStringValue(`{"ok":true,"elapsed":"` + time.Since(start).String() + "\"}") res = resp.SimpleStringValue(`{"ok":true,"elapsed":"` +
time.Since(start).String() + "\"}")
case RESP: case RESP:
if cleared { if cleared {
res = resp.IntegerValue(1) 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, "WHEREIN", keys_WHEREIN_test)
runStep(t, mc, "WHEREEVAL", keys_WHEREEVAL_test) runStep(t, mc, "WHEREEVAL", keys_WHEREEVAL_test)
runStep(t, mc, "TYPE", keys_TYPE_test) runStep(t, mc, "TYPE", keys_TYPE_test)
runStep(t, mc, "FLUSHDB", keys_FLUSHDB_test)
} }
func keys_BOUNDS_test(mc *mockServer) error { 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 { func keys_EXPIRE_test(mc *mockServer) error {
return mc.DoBatch([][]interface{}{ return mc.DoBatch(
{"SET", "mykey", "myid", "STRING", "value"}, {"OK"}, Do("SET", "mykey", "myid", "STRING", "value").OK(),
{"EXPIRE", "mykey", "myid", 1}, {1}, Do("EXPIRE", "mykey", "myid").Err("wrong number of arguments for 'expire' command"),
{time.Second / 4}, {}, // sleep Do("EXPIRE", "mykey", "myid", "y").Err("invalid argument 'y'"),
{"GET", "mykey", "myid"}, {"value"}, Do("EXPIRE", "mykey", "myid", 1).Str("1"),
{time.Second}, {}, // sleep Do("EXPIRE", "mykey", "myid", 1).JSON().OK(),
{"GET", "mykey", "myid"}, {nil}, 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 { func keys_FSET_test(mc *mockServer) error {
return mc.DoBatch([][]interface{}{ return mc.DoBatch([][]interface{}{
@ -435,3 +448,26 @@ func keys_TYPE_test(mc *mockServer) error {
Do("TYPE", "mykey").JSON().Str(`{"ok":true,"type":"hash"}`), 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" "path/filepath"
"runtime" "runtime"
"strings" "strings"
"time"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
) )
type IO struct { type IO struct {
args []any args []any
json bool json bool
out any out any
sleep bool
dur time.Duration
} }
func Do(args ...any) *IO { 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 { type ioVisitor struct {
fset *token.FileSet fset *token.FileSet
ln int ln int
@ -222,6 +229,10 @@ func (cmd *IO) deepError(index int, err error) error {
} }
func (mc *mockServer) doIOTest(index int, cmd *IO) error { func (mc *mockServer) doIOTest(index int, cmd *IO) error {
if cmd.sleep {
time.Sleep(cmd.dur)
return nil
}
// switch json mode if desired // switch json mode if desired
if cmd.json { if cmd.json {
if !mc.ioJSON { if !mc.ioJSON {