From d7ad01e5934b5f59b693ce8584c2b5198cebf353 Mon Sep 17 00:00:00 2001 From: tidwall Date: Fri, 23 Sep 2022 11:40:48 -0700 Subject: [PATCH] Better FLUSHDB/EXPIRES tests --- internal/server/crud.go | 45 +++++++++++++++++++++++++---------- tests/keys_test.go | 52 ++++++++++++++++++++++++++++++++++------- tests/mock_io_test.go | 17 +++++++++++--- 3 files changed, 91 insertions(+), 23 deletions(-) diff --git a/internal/server/crud.go b/internal/server/crud.go index 651b5c06..4cb297a9 100644 --- a/internal/server/crud.go +++ b/internal/server/crud.go @@ -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) diff --git a/tests/keys_test.go b/tests/keys_test.go index 1d3fefcf..3d4248cd 100644 --- a/tests/keys_test.go +++ b/tests/keys_test.go @@ -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(""), + 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(), + ) +} diff --git a/tests/mock_io_test.go b/tests/mock_io_test.go index ba19ddc6..72a24e6b 100644 --- a/tests/mock_io_test.go +++ b/tests/mock_io_test.go @@ -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 {