Skip to content

Commit

Permalink
Add integration tests for SET commands (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dhroov7 authored Oct 16, 2024
1 parent 60b68da commit 28acf44
Show file tree
Hide file tree
Showing 4 changed files with 378 additions and 0 deletions.
56 changes: 56 additions & 0 deletions internal/tests/integration/commands/get_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package commands

import (
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestGet(t *testing.T) {
exec, err := NewHTTPCommandExecutor()
if err != nil {
t.Fatal(err)
}

defer exec.FlushDB()

testCases := []TestCase{
{
Name: "Get with expiration",
Commands: []HTTPCommand{
{Command: "SET", Body: []string{"k", "v", "EX", "4"}},
{Command: "GET", Body: []string{"k"}},
{Command: "GET", Body: []string{"k"}},
},
Result: []TestCaseResult{
{Expected: "OK"},
{Expected: "v"},
{Expected: "(nil)"},
},
Delays: []time.Duration{0, 0, 5 * time.Second},
},
}

for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
for i, cmd := range tc.Commands {
if tc.Delays[i] > 0 {
time.Sleep(tc.Delays[i])
}
response, err := exec.FireCommand(cmd)
if err != nil {
t.Logf("error in executing command: %s - %v", cmd.Command, err)
}

result := tc.Result[i]
if result.ErrorExpected {
assert.NotNil(t, err)
assert.Equal(t, result.Expected, err.Error())
} else {
assert.Equal(t, result.Expected, response)
}
}
})
}
}
143 changes: 143 additions & 0 deletions internal/tests/integration/commands/incr_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package commands

import (
"math"
"strconv"
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestIncr(t *testing.T) {
exec, err := NewHTTPCommandExecutor()
if err != nil {
t.Fatal(err)
}

defer exec.FlushDB()

testCases := []TestCase{
{
Name: "Increment multiple keys",
Commands: []HTTPCommand{
{Command: "SET", Body: []string{"key1", "0"}},
{Command: "INCR", Body: []string{"key1"}},
{Command: "INCR", Body: []string{"key1"}},
{Command: "INCR", Body: []string{"key2"}},
{Command: "GET", Body: []string{"key1"}},
{Command: "GET", Body: []string{"key2"}},
},
Result: []TestCaseResult{
{Expected: "OK"},
{Expected: "1"},
{Expected: "2"},
{Expected: "1"},
{Expected: "2"},
{Expected: "1"},
},
},
{
Name: "Increment from min int64",
Commands: []HTTPCommand{
{Command: "SET", Body: []string{"min_int", strconv.Itoa(math.MinInt64)}},
{Command: "INCR", Body: []string{"min_int"}},
{Command: "INCR", Body: []string{"min_int"}},
},
Result: []TestCaseResult{
{Expected: "OK"},
{Expected: strconv.FormatInt(math.MinInt64+1, 10)},
{Expected: strconv.FormatInt(math.MinInt64+2, 10)},
},
},
{
Name: "Increment non-existent key",
Commands: []HTTPCommand{
{Command: "INCR", Body: []string{"non_existent"}},
{Command: "GET", Body: []string{"non_existent"}},
{Command: "INCR", Body: []string{"non_existent"}},
},
Result: []TestCaseResult{
{Expected: "1"},
{Expected: "1"},
{Expected: "2"},
},
},
{
Name: "Increment string representing integers",
Commands: []HTTPCommand{
{Command: "SET", Body: []string{"str_int1", "42"}},
{Command: "INCR", Body: []string{"str_int1"}},
{Command: "SET", Body: []string{"str_int2", "-10"}},
{Command: "INCR", Body: []string{"str_int2"}},
{Command: "SET", Body: []string{"str_int3", "0"}},
{Command: "INCR", Body: []string{"str_int3"}},
},
Result: []TestCaseResult{
{Expected: "OK"},
{Expected: "43"},
{Expected: "OK"},
{Expected: "-9"},
{Expected: "OK"},
{Expected: "1"},
},
},
{
Name: "Increment with expiry",
Commands: []HTTPCommand{
{Command: "SET", Body: []string{"expiry_key", "0", "EX", "1"}},
{Command: "INCR", Body: []string{"expiry_key"}},
{Command: "INCR", Body: []string{"expiry_key"}},
{Command: "GET", Body: []string{"expiry_key"}},
},
Result: []TestCaseResult{
{Expected: "OK"},
{Expected: "1"},
{Expected: "2"},
{Expected: "(nil)"},
},
Delays: []time.Duration{0, 0, 0, 2 * time.Second},
},
{
Name: "Increment non-integer values",
Commands: []HTTPCommand{
{Command: "SET", Body: []string{"float_key", "3.14"}},
{Command: "INCR", Body: []string{"float_key"}},
{Command: "SET", Body: []string{"string_key", "hello"}},
{Command: "INCR", Body: []string{"string_key"}},
{Command: "SET", Body: []string{"bool_key", "true"}},
{Command: "INCR", Body: []string{"bool_key"}},
},
Result: []TestCaseResult{
{Expected: "OK"},
{ErrorExpected: true, Expected: "(error) ERR WRONGTYPE Operation against a key holding the wrong kind of value"},
{Expected: "OK"},
{ErrorExpected: true, Expected: "(error) ERR WRONGTYPE Operation against a key holding the wrong kind of value"},
{Expected: "OK"},
{ErrorExpected: true, Expected: "(error) ERR WRONGTYPE Operation against a key holding the wrong kind of value"},
},
},
}

for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
for i, cmd := range tc.Commands {
if tc.Delays != nil && tc.Delays[i] > 0 {
time.Sleep(tc.Delays[i])
}
response, err := exec.FireCommand(cmd)
if err != nil {
t.Logf("error in executing command: %s - %v", cmd.Command, err)
}

result := tc.Result[i]
if result.ErrorExpected {
assert.NotNil(t, err)
assert.Equal(t, result.Expected, err.Error())
} else {
assert.Equal(t, result.Expected, response)
}
}
})
}
}
177 changes: 177 additions & 0 deletions internal/tests/integration/commands/set_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package commands

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestSet(t *testing.T) {
exec, err := NewHTTPCommandExecutor()
if err != nil {
t.Fatal(err)
}

defer exec.FlushDB()

testCases := []TestCase{
{
Name: "Set and Get Simple Value",
Commands: []HTTPCommand{
{Command: "SET", Body: []string{"k", "v"}},
{Command: "GET", Body: []string{"k"}},
},
Result: []TestCaseResult{
{Expected: "OK"},
{Expected: "v"},
},
},
{
Name: "Set and Get Integer Value",
Commands: []HTTPCommand{
{Command: "SET", Body: []string{"k", "123456789"}},
{Command: "GET", Body: []string{"k"}},
},
Result: []TestCaseResult{
{Expected: "OK"},
{Expected: "123456789"}, // This is Redis' scientific notation for large numbers
},
},
{
Name: "Overwrite Existing Key",
Commands: []HTTPCommand{
{Command: "SET", Body: []string{"k", "v1"}},
{Command: "SET", Body: []string{"k", "5"}},
{Command: "GET", Body: []string{"k"}},
},
Result: []TestCaseResult{
{Expected: "OK"},
{Expected: "OK"},
{Expected: "5"}, // As the value 5 is stored as a string
},
},
{
Name: "Set with EX and PX option",
Commands: []HTTPCommand{
{Command: "SET", Body: []string{"k", "v", "EX", "2", "PX", "2000"}},
},
Result: []TestCaseResult{
{ErrorExpected: true, Expected: "(error) ERR syntax error"},
},
},
{
Name: "XX on non-existing key",
Commands: []HTTPCommand{
{Command: "DEL", Body: []string{"a"}},
{Command: "SET", Body: []string{"a", "v", "XX"}},
{Command: "GET", Body: []string{"a"}},
},
Result: []TestCaseResult{
{Expected: "0"}, // DEL returns number of deleted keys
{Expected: "(nil)"},
{Expected: "(nil)"},
},
},
{
Name: "NX on non-existing key",
Commands: []HTTPCommand{
{Command: "DEL", Body: []string{"c"}},
{Command: "SET", Body: []string{"c", "v", "NX"}},
{Command: "GET", Body: []string{"c"}},
},
Result: []TestCaseResult{
{Expected: "0"}, // DEL returns number of deleted keys
{Expected: "OK"},
{Expected: "v"},
},
},
{
Name: "NX on existing key",
Commands: []HTTPCommand{
{Command: "DEL", Body: []string{"b"}},
{Command: "SET", Body: []string{"b", "v", "NX"}},
{Command: "GET", Body: []string{"b"}},
{Command: "SET", Body: []string{"b", "v", "NX"}},
},
Result: []TestCaseResult{
{Expected: "0"}, // DEL returns number of deleted keys
{Expected: "OK"},
{Expected: "v"},
{Expected: "(nil)"}, // NX fails because the key already exists
},
},
{
Name: "PXAT option with invalid unix time ms",
Commands: []HTTPCommand{
{Command: "SET", Body: []string{"k2", "v2", "PXAT", "123123"}},
{Command: "GET", Body: []string{"k2"}},
},
Result: []TestCaseResult{
{Expected: "OK"},
{Expected: "(nil)"}, // Invalid time causes key not to be set properly
},
},
{
Name: "XX on existing key",
Commands: []HTTPCommand{
{Command: "SET", Body: []string{"k", "v1"}},
{Command: "SET", Body: []string{"k", "v2", "XX"}},
{Command: "GET", Body: []string{"k"}},
},
Result: []TestCaseResult{
{Expected: "OK"},
{Expected: "OK"},
{Expected: "v2"},
},
},
{
Name: "Multiple XX operations",
Commands: []HTTPCommand{
{Command: "SET", Body: []string{"k", "v1"}},
{Command: "SET", Body: []string{"k", "v2", "XX"}},
{Command: "SET", Body: []string{"k", "v3", "XX"}},
{Command: "GET", Body: []string{"k"}},
},
Result: []TestCaseResult{
{Expected: "OK"},
{Expected: "OK"},
{Expected: "OK"},
{Expected: "v3"},
},
},
{
Name: "EX option",
Commands: []HTTPCommand{
{Command: "SET", Body: []string{"k", "v", "EX", "1"}},
{Command: "GET", Body: []string{"k"}},
{Command: "SLEEP", Body: []string{"2"}},
{Command: "GET", Body: []string{"k"}},
},
Result: []TestCaseResult{
{Expected: "OK"},
{Expected: "v"},
{Expected: "OK"},
{Expected: "(nil)"}, // After expiration
},
},
}

for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
for i, cmd := range tc.Commands {
response, err := exec.FireCommand(cmd)
if err != nil {
t.Logf("error in executing command: %s - %v", cmd.Command, err)
}

result := tc.Result[i]
if result.ErrorExpected {
assert.NotNil(t, err)
assert.Equal(t, result.Expected, err.Error())
} else {
assert.Equal(t, result.Expected, response)
}
}
})
}
}
2 changes: 2 additions & 0 deletions internal/tests/integration/commands/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"server/config"
"server/internal/db"
"server/internal/server"
"time"
)

type HTTPCommand struct {
Expand All @@ -35,6 +36,7 @@ type TestCase struct {
Name string
Commands []HTTPCommand
Result []TestCaseResult
Delays []time.Duration
}

func NewHTTPCommandExecutor() (*HTTPCommandExecutor, error) {
Expand Down

0 comments on commit 28acf44

Please sign in to comment.