Skip to content

Commit

Permalink
merge master
Browse files Browse the repository at this point in the history
  • Loading branch information
iamskp11 committed Sep 19, 2024
2 parents 144e03a + fccf6b4 commit 1577260
Show file tree
Hide file tree
Showing 13 changed files with 324 additions and 37 deletions.
41 changes: 41 additions & 0 deletions .github/ISSUE_TEMPLATE/report_command_bug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
name: Bug in DiceDB command
about: Use this template to report bug in any command behaviour vs Redis
title: 'Inconsistent `{CMD}`: <Describe the error in one concise line>'
labels: ''
assignees: ''

---

## Steps to reproduce

{steps_to_reproduce}

## Expected output

The expected output when the above set of commands (maybe when run on Redis)

```
{expected_output}
```

## Observed output

The observed output when the above set of commands when run on DiceDB

```
{observed_output}
```

## Expectations for resolution

This issue will be considered resolved when the following things are done

1. changes in the [`dice`](https://github.com/dicedb/dice) code to meet the expected behavior
2. addition of relevant test case to ensure we catch the regression

You can find the tests under the `tests` directory of the [`dice`](https://github.com/dicedb/dice) repository and the steps to run are in the [README file](https://github.com/dicedb/dice). Refer to the following links to set up DiceDB and Redis 7.2.5 locally

- [setup DiceDB locally](https://github.com/dicedb/dice)
- [setup Redis 7.2.5 locally](https://gist.github.com/arpitbbhayani/94aedf279349303ed7394197976b6843)
- [setup DiceDB CLI](https://github.com/dicedb/dice)
10 changes: 1 addition & 9 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,7 @@ $ git add <files required for the change>
$ git commit -m "Meaningful oneliner for the change"
$ git push origin <your issue branch>
After this, create a PullRequest in `github <https://github.com/dicedb/dice/pulls>`_. Include the following information in the description:
* The changes that are included in the PR.
* Design document, if any.
* Information on any implementation choices that were made.
* Evidence of sufficient testing. You ``MUST`` indicate the tests done, either manually or automated.
After this, create a PullRequest in `github <https://github.com/dicedb/docs/pulls>`_. Make sure you have linked the relevant Issue in the description with "Closes #number" or "Fixes #number".
```

- Once you receive comments on github on your changes, be sure to respond to them on github and address the concerns. If any discussions happen offline for the changes in question, make sure to capture the outcome of the discussion, so others can follow along as well.
Expand Down
11 changes: 9 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ func SetupConfig() {
setUpViperConfig(ConfigFileLocation)
return
}

// If no flags are set, use default configurations with prioritizing command line flags
mergeFlagsWithConfig()
}

func createConfigFile(configFilePath string) {
Expand Down Expand Up @@ -237,6 +240,12 @@ func setUpViperConfig(configFilePath string) {
}

// override default configurations with command line flags
mergeFlagsWithConfig()

log.Info("configurations loaded successfully.")
}

func mergeFlagsWithConfig() {
if RequirePass != utils.EmptyStr {
DiceConfig.Auth.Password = RequirePass
}
Expand All @@ -248,8 +257,6 @@ func setUpViperConfig(configFilePath string) {
if Port != DefaultPort {
DiceConfig.Server.Port = Port
}

log.Info("configurations loaded successfully.")
}

// This function checks if the config file is present or not at ConfigFileLocation
Expand Down
51 changes: 51 additions & 0 deletions integration_tests/commands/mset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,54 @@ func TestMset(t *testing.T) {
})
}
}
func TestMSETInconsistency(t *testing.T) {

conn := getLocalConnection()
defer conn.Close()

testCases := []struct {
name string
commands []string
expected []interface{}
}{
{
name: "MSET with one key-value pair",
commands: []string{"MSET k1 v1", "GET k1"},
expected: []interface{}{"OK", "v1"},
},
{
name: "MSET with multiple key-value pairs",
commands: []string{"MSET k1 v1 k2 v2", "GET k1", "GET k2"},
expected: []interface{}{"OK", "v1", "v2"},
},
{
name: "MSET with odd number of arguments",
commands: []string{"MSET k1 v1 k2"},
expected: []interface{}{"ERR wrong number of arguments for 'mset' command"},
},
{
name: "MSET with multiple key-value pairs",
commands: []string{"MSET k1 v1 k2 v2", "GET k1", "GET k2"},
expected: []interface{}{"OK", "v1", "v2"},
},
{
name: "MSET with integers arguments",
commands: []string{"MSET key1 12345 key2 67890", "GET key1", "GET key2"},
expected: []interface{}{"OK", int64(12345), int64(67890)},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// deleteTestKeys([]string{"k1", "k2"}, store)
FireCommand(conn, "DEL k1")
FireCommand(conn, "DEL k1")

for i, cmd := range tc.commands {
result := FireCommand(conn, cmd)
assert.DeepEqual(t, tc.expected[i], result)
}
})
}

}
70 changes: 70 additions & 0 deletions integration_tests/commands/type_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package commands

import (
"testing"

"gotest.tools/v3/assert"
)

func TestType(t *testing.T) {
conn := getLocalConnection()
defer conn.Close()

testCases := []struct {
name string
commands []string
expected []interface{}
}{
{
name: "TYPE with invalid number of arguments",
commands: []string{"TYPE"},
expected: []interface{}{"ERR wrong number of arguments for 'type' command"},
},
{
name: "TYPE for non-existent key",
commands: []string{"TYPE k1"},
expected: []interface{}{"none"},
},
{
name: "TYPE for key with String value",
commands: []string{"SET k1 v1", "TYPE k1"},
expected: []interface{}{"OK", "string"},
},
{
name: "TYPE for key with List value",
commands: []string{"LPUSH k1 v1", "TYPE k1"},
expected: []interface{}{"OK", "list"},
},
{
name: "TYPE for key with Set value",
commands: []string{"SADD k1 v1", "TYPE k1"},
expected: []interface{}{int64(1), "set"},
},
{
name: "TYPE for key with Hash value",
commands: []string{"HSET k1 field1 v1", "TYPE k1"},
expected: []interface{}{int64(1), "hash"},
},
{
name: "TYPE for key with value created from SETBIT command",
commands: []string{"SETBIT k1 1 1", "TYPE k1"},
expected: []interface{}{int64(0), "string"},
},
{
name: "TYPE for key with value created from SETOP command",
commands: []string{"SET key1 \"foobar\"", "SET key2 \"abcdef\"", "BITOP AND dest key1 key2", "TYPE dest"},
expected: []interface{}{"OK", "OK", int64(6), "string"},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
FireCommand(conn, "DEL k1")

for i, cmd := range tc.commands {
result := FireCommand(conn, cmd)
assert.Equal(t, tc.expected[i], result, "Value mismatch for cmd %s", cmd)
}
})
}
}
10 changes: 7 additions & 3 deletions internal/auth/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import (
"sync"
"time"

"github.com/charmbracelet/log"
"github.com/dicedb/dice/internal/server/utils"

"github.com/dicedb/dice/config"
"golang.org/x/crypto/bcrypt"
)

const (
DefaultUserName = "default"
AuthCmd = "AUTH"
AuthCmd = "AUTH"

SessionStatusPending SessionStatusT = SessionStatusT(0)
SessionStatusActive SessionStatusT = SessionStatusT(1)
Expand Down Expand Up @@ -80,6 +80,10 @@ func (user *User) SetPassword(password string) (err error) {
var (
hashedPassword []byte
)
if password == utils.EmptyStr {
log.Warn("WARNING: DiceDB is running without authentication. Consider setting a password.")
}

if hashedPassword, err = bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost); err != nil {
return
}
Expand Down Expand Up @@ -125,7 +129,7 @@ func (session *Session) Validate(username, password string) error {
if user, err = UserStore.Get(username); err != nil {
return err
}
if username == DefaultUserName && len(user.Passwords) == 0 {
if username == config.DiceConfig.Auth.UserName && len(user.Passwords) == 0 {
session.Activate(user)
return nil
}
Expand Down
4 changes: 2 additions & 2 deletions internal/auth/session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func TestSessionIsActive(t *testing.T) {

func TestSessionActivate(t *testing.T) {
session := NewSession()
user := &User{Username: DefaultUserName}
user := &User{Username: config.DiceConfig.Auth.UserName}

session.Activate(user)

Expand All @@ -119,7 +119,7 @@ func TestSessionActivate(t *testing.T) {
}

func TestSessionValidate(t *testing.T) {
username := DefaultUserName
username := config.DiceConfig.Auth.UserName
password := "testpassword"

user, _ := UserStore.Add(username)
Expand Down
8 changes: 8 additions & 0 deletions internal/eval/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,13 @@ var (
Arity: 3,
KeySpecs: KeySpecs{BeginIndex: 1},
}
typeCmdMeta = DiceCmdMeta{
Name: "TYPE",
Info: `Returns the string representation of the type of the value stored at key. The different types that can be returned are: string, list, set, zset, hash and stream.`,
Eval: evalTYPE,
Arity: 1,
KeySpecs: KeySpecs{BeginIndex: 1},
}
)

func init() {
Expand Down Expand Up @@ -860,6 +867,7 @@ func init() {
DiceCmds["HLEN"] = hlenCmdMeta
DiceCmds["SELECT"] = selectCmdMeta
DiceCmds["JSON.NUMINCRBY"] = jsonnumincrbyCmdMeta
DiceCmds["TYPE"] = typeCmdMeta
}

// Function to convert DiceCmdMeta to []interface{}
Expand Down
43 changes: 39 additions & 4 deletions internal/eval/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"github.com/bytedance/sonic"
"github.com/charmbracelet/log"
"github.com/dicedb/dice/config"
"github.com/dicedb/dice/internal/auth"
"github.com/dicedb/dice/internal/clientio"
"github.com/dicedb/dice/internal/comm"
diceerrors "github.com/dicedb/dice/internal/errors"
Expand Down Expand Up @@ -82,7 +81,7 @@ func EvalAUTH(args []string, c *comm.Client) []byte {
return diceerrors.NewErrWithMessage("AUTH <password> called without any password configured for the default user. Are you sure your configuration is correct?")
}

username := auth.DefaultUserName
username := config.DiceConfig.Auth.UserName
var password string

if len(args) == 1 {
Expand Down Expand Up @@ -239,7 +238,16 @@ func evalMSET(args []string, store *dstore.Store) []byte {
for i := 0; i < len(args); i += 2 {
key, value := args[i], args[i+1]
oType, oEnc := deduceTypeEncoding(value)
insertMap[key] = store.NewObj(value, exDurationMs, oType, oEnc)
var storedValue interface{}
switch oEnc {
case object.ObjEncodingInt:
storedValue, _ = strconv.ParseInt(value, 10, 64)
case object.ObjEncodingEmbStr, object.ObjEncodingRaw:
storedValue = value
default:
return clientio.Encode(fmt.Errorf("ERR unsupported encoding: %d", oEnc), false)
}
insertMap[key] = store.NewObj(storedValue, exDurationMs, oType, oEnc)
}

store.PutAll(insertMap)
Expand Down Expand Up @@ -3620,4 +3628,31 @@ func evalJSONOBJKEYS(args []string, store *dstore.Store) []byte {
}

return clientio.Encode(keysList, false)
}
}

func evalTYPE(args []string, store *dstore.Store) []byte {
if len(args) != 1 {
return diceerrors.NewErrArity("TYPE")
}
key := args[0]
obj := store.Get(key)
if obj == nil {
return clientio.Encode("none", false)
}

var typeStr string
switch oType, _ := object.ExtractTypeEncoding(obj); oType {
case object.ObjTypeString, object.ObjTypeInt, object.ObjTypeByteArray:
typeStr = "string"
case object.ObjTypeByteList:
typeStr = "list"
case object.ObjTypeSet:
typeStr = "set"
case object.ObjTypeHashMap:
typeStr = "hash"
default:
typeStr = "non-supported type"
}

return clientio.Encode(typeStr, false)
}
Loading

0 comments on commit 1577260

Please sign in to comment.