diff --git a/config/validator.go b/config/validator.go index 95872aad3..b88205086 100644 --- a/config/validator.go +++ b/config/validator.go @@ -115,7 +115,7 @@ func applyDefaultValuesFromTags(config *Config, fieldName string) error { func validateWALConfig(sl validator.StructLevel) { config := sl.Current().Interface().(Config) - + // LogDir validation if config.WAL.LogDir == "" { sl.ReportError(config.WAL.LogDir, "LogDir", "LogDir", "required", "cannot be empty") diff --git a/integration_tests/commands/http/json_test.go b/integration_tests/commands/http/json_test.go index a1b8aeb31..7fca34497 100644 --- a/integration_tests/commands/http/json_test.go +++ b/integration_tests/commands/http/json_test.go @@ -74,8 +74,6 @@ func runIntegrationTests(t *testing.T, exec *HTTPCommandExecutor, testCases []In case "range": assert.True(t, result.(float64) <= out.(float64) && result.(float64) > 0, "Expected %v to be within 0 to %v", result, out) case "json_equal": - // fmt.Println("hi expected : ", out) - // fmt.Println("hi actual :", result) assert.JSONEq(t, out.(string), result.(string)) case "deep_equal": assert.ElementsMatch(t, result.([]interface{}), out.([]interface{})) @@ -1794,162 +1792,162 @@ func TestJSONARRINDEX(t *testing.T) { exec.FireCommand(HTTPCommand{Command: "DEL", Body: map[string]interface{}{"key": "key"}}) defer exec.FireCommand(HTTPCommand{Command: "DEL", Body: map[string]interface{}{"key": "key"}}) - normalArray := `[0,1,2,3,4,3]` - nestedArray := `{"arrays":[{"arr":[1,2,3]},{"arr":[2,3,4]},{"arr":[1]}]}` + normalArray := `[0,1,2,3,4,3]` + nestedArray := `{"arrays":[{"arr":[1,2,3]},{"arr":[2,3,4]},{"arr":[1]}]}` nestedArray2 := `{"a":[3],"nested":{"a":{"b":2,"c":1}}}` testCases := []IntegrationTestCase{ { - name: "should return array index when given element is present", + name: "should return array index when given element is present", commands: []HTTPCommand{ {Command: "JSON.SET", Body: map[string]interface{}{"key": "key", "path": "$", "json": json.RawMessage(normalArray)}}, {Command: "JSON.ARRINDEX", Body: map[string]interface{}{"key": "key", "path": "$", "value": 3}}, }, - expected: []interface{}{"OK", []interface{}{float64(3)}}, + expected: []interface{}{"OK", []interface{}{float64(3)}}, assertType: []string{"equal", "equal"}, cleanUp: []HTTPCommand{ {Command: "DEL", Body: map[string]interface{}{"key": "key"}}, }, }, { - name: "should return -1 when given element is not present", + name: "should return -1 when given element is not present", commands: []HTTPCommand{ {Command: "JSON.SET", Body: map[string]interface{}{"key": "key", "path": "$", "json": json.RawMessage(normalArray)}}, {Command: "JSON.ARRINDEX", Body: map[string]interface{}{"key": "key", "path": "$", "value": 10}}, }, - expected: []interface{}{"OK", []interface{}{float64(-1)}}, + expected: []interface{}{"OK", []interface{}{float64(-1)}}, assertType: []string{"equal", "equal"}, cleanUp: []HTTPCommand{ {Command: "DEL", Body: map[string]interface{}{"key": "key"}}, }, }, { - name: "should return array index with start optional param provided", + name: "should return array index with start optional param provided", commands: []HTTPCommand{ {Command: "JSON.SET", Body: map[string]interface{}{"key": "key", "path": "$", "json": json.RawMessage(normalArray)}}, {Command: "JSON.ARRINDEX", Body: map[string]interface{}{"key": "key", "path": "$", "values": []string{"3", "4"}}}, }, - expected: []interface{}{"OK", []interface{}{float64(5)}}, + expected: []interface{}{"OK", []interface{}{float64(5)}}, assertType: []string{"equal", "equal"}, cleanUp: []HTTPCommand{ {Command: "DEL", Body: map[string]interface{}{"key": "key"}}, }, }, { - name: "should return array index with start and stop optional param provided", + name: "should return array index with start and stop optional param provided", commands: []HTTPCommand{ {Command: "JSON.SET", Body: map[string]interface{}{"key": "key", "path": "$", "json": json.RawMessage(normalArray)}}, {Command: "JSON.ARRINDEX", Body: map[string]interface{}{"key": "key", "path": "$", "values": []string{"4", "4", "5"}}}, }, - expected: []interface{}{"OK", []interface{}{float64(4)}}, + expected: []interface{}{"OK", []interface{}{float64(4)}}, assertType: []string{"equal", "equal"}, cleanUp: []HTTPCommand{ {Command: "DEL", Body: map[string]interface{}{"key": "key"}}, }, }, { - name: "should return -1 with start and stop optional param provided where start > stop", + name: "should return -1 with start and stop optional param provided where start > stop", commands: []HTTPCommand{ {Command: "JSON.SET", Body: map[string]interface{}{"key": "key", "path": "$", "json": json.RawMessage(normalArray)}}, {Command: "JSON.ARRINDEX", Body: map[string]interface{}{"key": "key", "path": "$", "values": []string{"3", "2", "1"}}}, }, - expected: []interface{}{"OK", []interface{}{float64(-1)}}, + expected: []interface{}{"OK", []interface{}{float64(-1)}}, assertType: []string{"equal", "equal"}, cleanUp: []HTTPCommand{ {Command: "DEL", Body: map[string]interface{}{"key": "key"}}, }, }, { - name: "should return -1 with start (out of boud) and stop (out of bound) optional param provided", + name: "should return -1 with start (out of boud) and stop (out of bound) optional param provided", commands: []HTTPCommand{ {Command: "JSON.SET", Body: map[string]interface{}{"key": "key", "path": "$", "json": json.RawMessage(normalArray)}}, {Command: "JSON.ARRINDEX", Body: map[string]interface{}{"key": "key", "path": "$", "values": []string{"3", "6", "10"}}}, }, - expected: []interface{}{"OK", []interface{}{float64(-1)}}, + expected: []interface{}{"OK", []interface{}{float64(-1)}}, assertType: []string{"equal", "equal"}, cleanUp: []HTTPCommand{ {Command: "DEL", Body: map[string]interface{}{"key": "key"}}, }, }, { - name: "should return list of array indexes for nested json", + name: "should return list of array indexes for nested json", commands: []HTTPCommand{ {Command: "JSON.SET", Body: map[string]interface{}{"key": "key", "path": "$", "json": json.RawMessage(nestedArray)}}, {Command: "JSON.ARRINDEX", Body: map[string]interface{}{"key": "key", "path": "$.arrays.*.arr", "value": 3}}, }, - expected: []interface{}{"OK", []interface{}{float64(2), float64(1), float64(-1)}}, + expected: []interface{}{"OK", []interface{}{float64(2), float64(1), float64(-1)}}, assertType: []string{"equal", "equal"}, cleanUp: []HTTPCommand{ {Command: "DEL", Body: map[string]interface{}{"key": "key"}}, }, }, { - name: "should return list of array indexes for multiple json path", + name: "should return list of array indexes for multiple json path", commands: []HTTPCommand{ {Command: "JSON.SET", Body: map[string]interface{}{"key": "key", "path": "$", "json": json.RawMessage(nestedArray)}}, {Command: "JSON.ARRINDEX", Body: map[string]interface{}{"key": "key", "path": "$..arr", "value": 3}}, }, - expected: []interface{}{"OK", []interface{}{float64(2), float64(1), float64(-1)}}, + expected: []interface{}{"OK", []interface{}{float64(2), float64(1), float64(-1)}}, assertType: []string{"equal", "equal"}, cleanUp: []HTTPCommand{ {Command: "DEL", Body: map[string]interface{}{"key": "key"}}, }, }, { - name: "should return array of length 1 for nested json path, with index", + name: "should return array of length 1 for nested json path, with index", commands: []HTTPCommand{ {Command: "JSON.SET", Body: map[string]interface{}{"key": "key", "path": "$", "json": json.RawMessage(nestedArray)}}, {Command: "JSON.ARRINDEX", Body: map[string]interface{}{"key": "key", "path": "$.arrays[1].arr", "value": 3}}, }, - expected: []interface{}{"OK", []interface{}{float64(1)}}, + expected: []interface{}{"OK", []interface{}{float64(1)}}, assertType: []string{"equal", "equal"}, cleanUp: []HTTPCommand{ {Command: "DEL", Body: map[string]interface{}{"key": "key"}}, }, }, { - name: "should return empty array for nonexistent path in nested json", + name: "should return empty array for nonexistent path in nested json", commands: []HTTPCommand{ {Command: "JSON.SET", Body: map[string]interface{}{"key": "key", "path": "$", "json": json.RawMessage(nestedArray)}}, {Command: "JSON.ARRINDEX", Body: map[string]interface{}{"key": "key", "path": "$..arr1", "value": 3}}, }, - expected: []interface{}{"OK", []interface{}{}}, + expected: []interface{}{"OK", []interface{}{}}, assertType: []string{"equal", "equal"}, cleanUp: []HTTPCommand{ {Command: "DEL", Body: map[string]interface{}{"key": "key"}}, }, }, { - name: "should return -1 for each nonexisting value in nested json", + name: "should return -1 for each nonexisting value in nested json", commands: []HTTPCommand{ {Command: "JSON.SET", Body: map[string]interface{}{"key": "key", "path": "$", "json": json.RawMessage(nestedArray)}}, {Command: "JSON.ARRINDEX", Body: map[string]interface{}{"key": "key", "path": "$..arr", "value": 5}}, }, - expected: []interface{}{"OK", []interface{}{float64(-1), float64(-1), float64(-1)}}, + expected: []interface{}{"OK", []interface{}{float64(-1), float64(-1), float64(-1)}}, assertType: []string{"equal", "equal"}, cleanUp: []HTTPCommand{ {Command: "DEL", Body: map[string]interface{}{"key": "key"}}, }, }, { - name: "should return nil for non-array path and -1 for array path if value DNE", + name: "should return nil for non-array path and -1 for array path if value DNE", commands: []HTTPCommand{ {Command: "JSON.SET", Body: map[string]interface{}{"key": "key", "path": "$", "json": json.RawMessage(nestedArray2)}}, {Command: "JSON.ARRINDEX", Body: map[string]interface{}{"key": "key", "path": "$..a", "value": 2}}, }, - expected: []interface{}{"OK", []interface{}{float64(-1), nil}}, + expected: []interface{}{"OK", []interface{}{float64(-1), nil}}, assertType: []string{"equal", "deep_equal"}, cleanUp: []HTTPCommand{ {Command: "DEL", Body: map[string]interface{}{"key": "key"}}, }, }, { - name: "should return nil for non-array path if value DNE and valid index for array path if value exists", + name: "should return nil for non-array path if value DNE and valid index for array path if value exists", commands: []HTTPCommand{ {Command: "JSON.SET", Body: map[string]interface{}{"key": "key", "path": "$", "json": json.RawMessage(nestedArray2)}}, {Command: "JSON.ARRINDEX", Body: map[string]interface{}{"key": "key", "path": "$..a", "value": 3}}, }, - expected: []interface{}{"OK", []interface{}{float64(0), nil}}, + expected: []interface{}{"OK", []interface{}{float64(0), nil}}, assertType: []string{"equal", "deep_equal"}, cleanUp: []HTTPCommand{ {Command: "DEL", Body: map[string]interface{}{"key": "key"}}, @@ -1960,4 +1958,4 @@ func TestJSONARRINDEX(t *testing.T) { preTestChecksCommand := HTTPCommand{Command: "DEL", Body: map[string]interface{}{"key": "key"}} postTestChecksCommand := HTTPCommand{Command: "DEL", Body: map[string]interface{}{"key": "key"}} runIntegrationTests(t, exec, testCases, preTestChecksCommand, postTestChecksCommand) -} \ No newline at end of file +} diff --git a/internal/eval/commands.go b/internal/eval/commands.go index 640acb12c..d3238bdd0 100644 --- a/internal/eval/commands.go +++ b/internal/eval/commands.go @@ -615,9 +615,9 @@ var ( Name: "JSON.ARRINDEX", Info: `JSON.ARRINDEX key path value [start [stop]] Search for the first occurrence of a JSON value in an array`, - NewEval: evalJSONARRINDEX, - Arity: -3, - KeySpecs: KeySpecs{BeginIndex: 1}, + NewEval: evalJSONARRINDEX, + Arity: -3, + KeySpecs: KeySpecs{BeginIndex: 1}, IsMigrated: true, } diff --git a/internal/eval/countminsketch.go b/internal/eval/countminsketch.go index 9d8128b05..5a69467d4 100644 --- a/internal/eval/countminsketch.go +++ b/internal/eval/countminsketch.go @@ -297,7 +297,7 @@ func DeserializeCMS(buffer *bytes.Reader) (*CountMinSketch, error) { if err := binary.Read(buffer, binary.BigEndian, &count); err != nil { return nil, err } - fmt.Println(depth, width, count, buffer.Len()) + // fmt.Println(depth, width, count, buffer.Len()) // Validate data size expectedSize := int(depth * width * 8) // Each uint64 takes 8 bytes if buffer.Len() <= expectedSize { diff --git a/internal/eval/eval_test.go b/internal/eval/eval_test.go index 0e53297b0..646a87d10 100644 --- a/internal/eval/eval_test.go +++ b/internal/eval/eval_test.go @@ -21,7 +21,6 @@ import ( "encoding/base64" "errors" "fmt" - "github.com/dicedb/dice/internal/cmd" "math" "reflect" "strconv" @@ -33,6 +32,7 @@ import ( "github.com/bytedance/sonic" "github.com/dicedb/dice/config" "github.com/dicedb/dice/internal/clientio" + "github.com/dicedb/dice/internal/cmd" diceerrors "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/eval/sortedset" "github.com/dicedb/dice/internal/object" @@ -47,7 +47,6 @@ type evalTestCase struct { setup func() input []string output []byte - validator func(output []byte) newValidator func(output interface{}) migratedOutput EvalResponse } @@ -4367,11 +4366,7 @@ func runEvalTests(t *testing.T, tests map[string]evalTestCase, evalFunc func([]s output := evalFunc(tc.input, store) - if tc.validator != nil { - tc.validator(output) - } else { - assert.Equal(t, string(tc.output), string(output)) - } + assert.Equal(t, string(tc.output), string(output)) }) } } @@ -4386,7 +4381,6 @@ func runMigratedEvalTests(t *testing.T, tests map[string]evalTestCase, evalFunc } output := evalFunc(tc.input, store) - if tc.newValidator != nil { if tc.migratedOutput.Error != nil { tc.newValidator(tc.migratedOutput.Error) @@ -4405,8 +4399,8 @@ func runMigratedEvalTests(t *testing.T, tests map[string]evalTestCase, evalFunc // TODO: Make this generic so that all kind of slices can be handled if b, ok := output.Result.([]byte); ok && tc.migratedOutput.Result != nil { if expectedBytes, ok := tc.migratedOutput.Result.([]byte); ok { - fmt.Println(string(b)) - fmt.Println(string(expectedBytes)) + // fmt.Println(string(b)) + // fmt.Println(string(expectedBytes)) assert.True(t, bytes.Equal(b, expectedBytes), "expected and actual byte slices should be equal") } } else if a, ok := output.Result.([]string); ok && tc.migratedOutput.Result != nil { @@ -5274,7 +5268,7 @@ func testEvalJSONARRPOP(t *testing.T, store *dstore.Store) { }, input: []string{"MOCK_KEY", "$", "2"}, output: []byte(":0\r\n"), - validator: func(output []byte) { + newValidator: func(output interface{}) { key := "MOCK_KEY" obj := store.Get(key) want := []interface{}{float64(0), float64(1), float64(3), float64(4), float64(5)} @@ -5297,7 +5291,7 @@ func testEvalJSONARRPOP(t *testing.T, store *dstore.Store) { }, input: []string{"MOCK_KEY", "$.b", "2"}, output: []byte("*1\r\n:2\r\n"), - validator: func(output []byte) { + newValidator: func(output interface{}) { key := "MOCK_KEY" path := "$.b" obj := store.Get(key) @@ -5319,30 +5313,7 @@ func testEvalJSONARRPOP(t *testing.T, store *dstore.Store) { }, }, } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - store = setupTest(store) - - if tt.setup != nil { - tt.setup() - } - response := evalJSONARRPOP(tt.input, store) - - if tt.migratedOutput.Result != nil { - if slice, ok := tt.migratedOutput.Result.([]interface{}); ok { - assert.Equal(t, slice, response.Result) - } else { - assert.Equal(t, tt.migratedOutput.Result, response.Result) - } - } - - if tt.migratedOutput.Error != nil { - assert.EqualError(t, response.Error, tt.migratedOutput.Error.Error()) - } else { - assert.NoError(t, response.Error) - } - }) - } + runMigratedEvalTests(t, tests, evalJSONARRPOP, store) } func testEvalTYPE(t *testing.T, store *dstore.Store) { @@ -6747,11 +6718,12 @@ func testEvalAPPEND(t *testing.T, store *dstore.Store) { }, input: []string{"key", "123"}, migratedOutput: EvalResponse{Result: 3, Error: nil}, - validator: func(output []byte) { + newValidator: func(output interface{}) { obj := store.Get("key") oType := obj.Type if oType != object.ObjTypeInt { t.Errorf("unexpected encoding") + return } }, }, @@ -6802,11 +6774,12 @@ func testEvalAPPEND(t *testing.T, store *dstore.Store) { }, input: []string{"key", "2"}, migratedOutput: EvalResponse{Result: 2, Error: nil}, - validator: func(output []byte) { + newValidator: func(output interface{}) { obj := store.Get("key") oType := obj.Type if oType != object.ObjTypeString { t.Errorf("unexpected encoding") + return } }, }, @@ -9356,7 +9329,7 @@ func testEvalLRANGE(t *testing.T, store *dstore.Store) { } func testEvalJSONARRINDEX(t *testing.T, store *dstore.Store) { - normalArray := `[0,1,2,3,4,3]` + normalArray := `[0,1,2,3,4,3]` tests := []evalTestCase{ { name: "nil value", @@ -9388,7 +9361,7 @@ func testEvalJSONARRINDEX(t *testing.T, store *dstore.Store) { input: []string{"EXISTING_KEY", "$", "3", "abc"}, migratedOutput: EvalResponse{ Result: nil, - Error: errors.New("ERR Couldn't parse as integer"), + Error: errors.New("ERR Couldn't parse as integer"), }, }, { @@ -9403,7 +9376,7 @@ func testEvalJSONARRINDEX(t *testing.T, store *dstore.Store) { input: []string{"EXISTING_KEY", "$", "3", "4", "abc"}, migratedOutput: EvalResponse{ Result: nil, - Error: errors.New("ERR Couldn't parse as integer"), + Error: errors.New("ERR Couldn't parse as integer"), }, }, { @@ -9418,7 +9391,7 @@ func testEvalJSONARRINDEX(t *testing.T, store *dstore.Store) { input: []string{"EXISTING_KEY", "$", "4", "4", "5"}, migratedOutput: EvalResponse{ Result: []interface{}{4}, - Error: nil, + Error: nil, }, }, } @@ -9440,4 +9413,4 @@ func testEvalJSONARRINDEX(t *testing.T, store *dstore.Store) { } }) } -} \ No newline at end of file +} diff --git a/internal/eval/store_eval.go b/internal/eval/store_eval.go index 9b3356ed1..7d6f2c6db 100644 --- a/internal/eval/store_eval.go +++ b/internal/eval/store_eval.go @@ -6979,9 +6979,9 @@ func evalJSONARRINDEX(args []string, store *dstore.Store) *EvalResponse { adjustedStart, adjustedStop := adjustIndices(start, stop, length) - if adjustedStart == -1 { - arrIndexList = append(arrIndexList, -1) - continue + if adjustedStart == -1 { + arrIndexList = append(arrIndexList, -1) + continue } // Range [start, stop) : start is inclusive, stop is exclusive @@ -7004,18 +7004,18 @@ func evalJSONARRINDEX(args []string, store *dstore.Store) *EvalResponse { return makeEvalResult(arrIndexList) } -// adjustIndices adjusts the start and stop indices for array traversal. -// It handles negative indices and ensures they are within the array bounds. -func adjustIndices(start, stop, length int) (adjustedStart, adjustedStop int) { +// adjustIndices adjusts the start and stop indices for array traversal. +// It handles negative indices and ensures they are within the array bounds. +func adjustIndices(start, stop, length int) (adjustedStart, adjustedStop int) { if length == 0 { - return -1, -1 + return -1, -1 } if start < 0 { - start += length + start += length } - if stop <= 0 { - stop += length + if stop <= 0 { + stop += length } if start < 0 { start = 0