From d0ad9c708e575e8d2f16c9df32f18792be7b458e Mon Sep 17 00:00:00 2001 From: RishabhC-137 Date: Mon, 14 Oct 2024 21:42:35 +0530 Subject: [PATCH] feat(tests): add Dice command integration tests (EXISTS, EXPIRE, EXPIREAT, EXPIRETIME) and package for validation --- .../commands/assertions/assertions.go | 26 +++++ .../tests/integration/commands/exists_test.go | 75 ++++++++++++++ .../tests/integration/commands/expire_test.go | 97 +++++++++++++++++++ .../integration/commands/expireat_test.go | 81 ++++++++++++++++ .../integration/commands/expiretime_test.go | 79 +++++++++++++++ .../tests/integration/commands/hget_test.go | 15 ++- .../integration/commands/hgetall_test.go | 17 ++-- .../tests/integration/commands/hset_test.go | 15 ++- 8 files changed, 377 insertions(+), 28 deletions(-) create mode 100644 internal/tests/integration/commands/assertions/assertions.go create mode 100644 internal/tests/integration/commands/exists_test.go create mode 100644 internal/tests/integration/commands/expire_test.go create mode 100644 internal/tests/integration/commands/expireat_test.go create mode 100644 internal/tests/integration/commands/expiretime_test.go diff --git a/internal/tests/integration/commands/assertions/assertions.go b/internal/tests/integration/commands/assertions/assertions.go new file mode 100644 index 0000000..029c74a --- /dev/null +++ b/internal/tests/integration/commands/assertions/assertions.go @@ -0,0 +1,26 @@ +package assertions + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// AssertResult checks the result of command execution against expected results. +// Parameters: +// - t: the testing context used for reporting errors. +// - err: the error returned from the command execution. +// - response: the response obtained from the command. +// - expected: the expected response string. +// - errorExpected: a flag indicating whether an error is expected. +func AssertResult(t *testing.T, err error, response, expected string, errorExpected bool) { + if errorExpected { + // Assert that an error occurred and check the error message. + assert.Error(t, err, "Expected an error but got none") + assert.EqualError(t, err, expected, "Error message does not match the expected message") + } else { + // Assert that no error occurred and check the response. + assert.NoError(t, err, "Expected no error but got one") + assert.Equal(t, expected, response, "Response does not match the expected value") + } +} diff --git a/internal/tests/integration/commands/exists_test.go b/internal/tests/integration/commands/exists_test.go new file mode 100644 index 0000000..826fdec --- /dev/null +++ b/internal/tests/integration/commands/exists_test.go @@ -0,0 +1,75 @@ +package commands + +import ( + "server/internal/tests/integration/commands/assertions" + "testing" +) + +func TestExists(t *testing.T) { + exec, err := NewHTTPCommandExecutor() + if err != nil { + t.Fatal(err) + } + + defer exec.FlushDB() + + testCases := []TestCase{ + { + Name: "EXISTS with a non-existent key", + Commands: []HTTPCommand{ + {Command: "EXISTS", Body: []string{"non_existent_key"}}, + }, + Result: []TestCaseResult{ + {Expected: "0"}, // Expecting 0 because the key should not exist + }, + }, + { + Name: "EXISTS with an existing key", + Commands: []HTTPCommand{ + {Command: "SET", Body: []string{"existing_key", "SomeValue"}}, + {Command: "EXISTS", Body: []string{"existing_key"}}, + }, + Result: []TestCaseResult{ + {Expected: "OK"}, // Expecting "OK" from the SET command + {Expected: "1"}, // Expecting 1 because the key should exist + }, + }, + { + Name: "EXISTS with multiple keys where some exist", + Commands: []HTTPCommand{ + {Command: "SET", Body: []string{"key1", "Value1"}}, + {Command: "SET", Body: []string{"key2", "Value2"}}, + {Command: "EXISTS", Body: []string{"key1", "key2", "non_existent_key"}}, + }, + Result: []TestCaseResult{ + {Expected: "OK"}, + {Expected: "OK"}, + {Expected: "2"}, // Expecting 2 because only key1 and key2 exist + }, + }, + { + Name: "EXISTS command with invalid number of arguments", + Commands: []HTTPCommand{ + {Command: "EXISTS", Body: []string{}}, // No arguments + }, + Result: []TestCaseResult{ + {ErrorExpected: true, Expected: "(error) ERR wrong number of arguments for 'exists' command"}, + }, + }, + } + + 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] + assertions.AssertResult(t, err, response, result.Expected, result.ErrorExpected) + + } + }) + } +} diff --git a/internal/tests/integration/commands/expire_test.go b/internal/tests/integration/commands/expire_test.go new file mode 100644 index 0000000..47cecab --- /dev/null +++ b/internal/tests/integration/commands/expire_test.go @@ -0,0 +1,97 @@ +package commands + +import ( + "server/internal/tests/integration/commands/assertions" + "testing" + "time" +) + +func TestExpire(t *testing.T) { + exec, err := NewHTTPCommandExecutor() + if err != nil { + t.Fatal(err) + } + + defer exec.FlushDB() + + testCases := []TestCase{ + { + Name: "EXPIRE on an existing key", + Commands: []HTTPCommand{ + {Command: "SET", Body: []string{"key_to_expire_1", "SomeValue"}}, + {Command: "EXPIRE", Body: []string{"key_to_expire_1", "1"}}, // 1 second expiration + }, + Result: []TestCaseResult{ + {Expected: "OK"}, + {Expected: "1"}, + }, + }, + { + Name: "Check expiration after delay", + Commands: []HTTPCommand{ + {Command: "SET", Body: []string{"key_to_expire_2", "SomeValue"}}, + {Command: "EXPIRE", Body: []string{"key_to_expire_2", "1"}}, + {Command: "GET", Body: []string{"key_to_expire_2"}}, // Check if key is still accessible + }, + Result: []TestCaseResult{ + {Expected: "OK"}, + {Expected: "1"}, + {Expected: "SomeValue"}, + }, + }, + { + Name: "Check key after waiting for expiration", + Commands: []HTTPCommand{ + {Command: "SET", Body: []string{"key_to_expire_3", "SomeValue"}}, + {Command: "EXPIRE", Body: []string{"key_to_expire_3", "3"}}, + {Command: "GET", Body: []string{"key_to_expire_3"}}, // Check if key is still accessible after waiting + }, + Result: []TestCaseResult{ + {Expected: "OK"}, + {Expected: "1"}, + {Expected: "(nil)"}, // Expecting (nil) after waiting + }, + }, + { + Name: "EXPIRE on a non-existent key", + Commands: []HTTPCommand{ + {Command: "EXPIRE", Body: []string{"non_existent_key", "1"}}, + }, + Result: []TestCaseResult{ + {Expected: "0"}, + }, + }, + { + Name: "EXPIRE with invalid number of arguments", + Commands: []HTTPCommand{ + {Command: "SET", Body: []string{"key_to_expire_4", "SomeValue"}}, + {Command: "EXPIRE", Body: []string{"key_to_expire_4", "1", "extra_argument"}}, + }, + Result: []TestCaseResult{ + {Expected: "OK"}, + {ErrorExpected: true, Expected: "(error) ERR Unsupported option extra_argument"}, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + for i, cmd := range tc.Commands { + if tc.Name == "Check key after waiting for expiration" && cmd.Command == "GET" { // Wait longer for expiration check + time.Sleep(4 * time.Second) // Longer than the expiration time + } + response, err := exec.FireCommand(cmd) + if err != nil { + t.Logf("Error executing command: %s - %v", cmd.Command, err) + } else { + t.Logf("Response for command %s: %s", cmd.Command, response) + } + + result := tc.Result[i] + + assertions.AssertResult(t, err, response, result.Expected, result.ErrorExpected) + } + + }) + } +} diff --git a/internal/tests/integration/commands/expireat_test.go b/internal/tests/integration/commands/expireat_test.go new file mode 100644 index 0000000..6b3fa29 --- /dev/null +++ b/internal/tests/integration/commands/expireat_test.go @@ -0,0 +1,81 @@ +package commands + +import ( + "server/internal/tests/integration/commands/assertions" + "strconv" + "testing" + "time" +) + +func TestExpireAt(t *testing.T) { + exec, err := NewHTTPCommandExecutor() + if err != nil { + t.Fatal(err) + } + + defer exec.FlushDB() + + testCases := []TestCase{ + { + Name: "EXPIREAT on a non-existent key", + Commands: []HTTPCommand{ + {Command: "EXPIREAT", Body: []string{"non_existent_key", "1660000000"}}, // Arbitrary timestamp + }, + Result: []TestCaseResult{ + {Expected: "0"}, // Expecting 0 because the key does not exist + }, + }, + { + Name: "EXPIREAT on an existing key with future timestamp", + Commands: []HTTPCommand{ + {Command: "SET", Body: []string{"temp_key", "temp_value"}}, + {Command: "EXPIREAT", Body: []string{"temp_key", strconv.FormatInt(time.Now().Add(30*time.Second).Unix(), 10)}}, // Future timestamp + {Command: "EXISTS", Body: []string{"temp_key"}}, // Check if the key exists immediately + }, + Result: []TestCaseResult{ + {Expected: "OK"}, + {Expected: "1"}, // Expecting 1 because EXPIREAT set the expiration successfully + {Expected: "1"}, // Key should still exist as it hasn't expired yet + }, + }, + { + Name: "EXPIREAT on an existing key with past timestamp", + Commands: []HTTPCommand{ + {Command: "SET", Body: []string{"past_key", "past_value"}}, + {Command: "EXPIREAT", Body: []string{"past_key", "1600000000"}}, // Past timestamp + {Command: "EXISTS", Body: []string{"past_key"}}, // Check if the key exists after expiration + }, + Result: []TestCaseResult{ + {Expected: "OK"}, + {Expected: "1"}, // EXPIREAT should execute successfully + {Expected: "0"}, // Key should not exist as it has already expired + }, + }, + { + Name: "EXPIREAT with invalid arguments", + Commands: []HTTPCommand{ + {Command: "EXPIREAT", Body: []string{"key_only"}}, // Missing timestamp + }, + Result: []TestCaseResult{ + {ErrorExpected: true, Expected: "(error) ERR wrong number of arguments for 'expireat' command"}, + }, + }, + } + + 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 executing command: %s - %v", cmd.Command, err) + } else { + t.Logf("Response for command %s: %s", cmd.Command, response) + } + + result := tc.Result[i] + assertions.AssertResult(t, err, response, result.Expected, result.ErrorExpected) + + } + }) + } +} diff --git a/internal/tests/integration/commands/expiretime_test.go b/internal/tests/integration/commands/expiretime_test.go new file mode 100644 index 0000000..c4454f2 --- /dev/null +++ b/internal/tests/integration/commands/expiretime_test.go @@ -0,0 +1,79 @@ +package commands + +import ( + "server/internal/tests/integration/commands/assertions" + "strconv" + "testing" + "time" +) + +func TestExpireTime(t *testing.T) { + exec, err := NewHTTPCommandExecutor() + if err != nil { + t.Fatal(err) + } + + defer exec.FlushDB() + + testCases := []TestCase{ + { + Name: "EXPIRETIME on a non-existent key", + Commands: []HTTPCommand{ + {Command: "EXPIRETIME", Body: []string{"non_existent_key"}}, + }, + Result: []TestCaseResult{ + {Expected: "-2"}, // Expecting -2 because the key does not exist + }, + }, + { + Name: "EXPIRETIME on an existing key with future expiration", + Commands: []HTTPCommand{ + {Command: "SET", Body: []string{"temp_key", "temp_value"}}, + {Command: "EXPIREAT", Body: []string{"temp_key", strconv.FormatInt(time.Now().Add(30*time.Second).Unix(), 10)}}, // Set future expiration + {Command: "EXPIRETIME", Body: []string{"temp_key"}}, // Retrieve expiration time + }, + Result: []TestCaseResult{ + {Expected: "OK"}, + {Expected: "1"}, // Indicating the EXPIREAT command was successful + {Expected: strconv.FormatInt(time.Now().Add(30*time.Second).Unix(), 10)}, // Future timestamp in seconds + }, + }, + { + Name: "EXPIRETIME on an existing key without expiration", + Commands: []HTTPCommand{ + {Command: "SET", Body: []string{"persist_key", "persistent_value"}}, + {Command: "EXPIRETIME", Body: []string{"persist_key"}}, // Check expiration time + }, + Result: []TestCaseResult{ + {Expected: "OK"}, + {Expected: "-1"}, // Expecting -1 because no expiration is set + }, + }, + { + Name: "EXPIRETIME with invalid arguments", + Commands: []HTTPCommand{ + {Command: "EXPIRETIME", Body: []string{}}, // Missing key argument + }, + Result: []TestCaseResult{ + {ErrorExpected: true, Expected: "(error) ERR wrong number of arguments for 'expiretime' command"}, + }, + }, + } + + 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 executing command: %s - %v", cmd.Command, err) + } else { + t.Logf("Response for command %s: %s", cmd.Command, response) + } + + result := tc.Result[i] + assertions.AssertResult(t, err, response, result.Expected, result.ErrorExpected) + + } + }) + } +} diff --git a/internal/tests/integration/commands/hget_test.go b/internal/tests/integration/commands/hget_test.go index b5205c5..4a81701 100644 --- a/internal/tests/integration/commands/hget_test.go +++ b/internal/tests/integration/commands/hget_test.go @@ -1,9 +1,8 @@ package commands import ( + "server/internal/tests/integration/commands/assertions" "testing" - - "github.com/stretchr/testify/assert" ) func TestHGet(t *testing.T) { @@ -73,16 +72,14 @@ func TestHGet(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) + t.Logf("Error executing command: %s - %v", cmd.Command, err) + } else { + t.Logf("Response for command %s: %s", cmd.Command, response) } 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) - } + assertions.AssertResult(t, err, response, result.Expected, result.ErrorExpected) + } }) } diff --git a/internal/tests/integration/commands/hgetall_test.go b/internal/tests/integration/commands/hgetall_test.go index cd99f11..4171e06 100644 --- a/internal/tests/integration/commands/hgetall_test.go +++ b/internal/tests/integration/commands/hgetall_test.go @@ -1,9 +1,8 @@ package commands import ( + "server/internal/tests/integration/commands/assertions" "testing" - - "github.com/stretchr/testify/assert" ) func TestHGetAll(t *testing.T) { @@ -18,7 +17,7 @@ func TestHGetAll(t *testing.T) { { Name: "HGETALL with a non-existent key", Commands: []HTTPCommand{ - {Command: "HGETALL", Body: []string{"user", "name"}}, + {Command: "HGETALL", Body: []string{"user"}}, }, Result: []TestCaseResult{ {Expected: ""}, @@ -62,16 +61,14 @@ func TestHGetAll(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) + t.Logf("Error executing command: %s - %v", cmd.Command, err) + } else { + t.Logf("Response for command %s: %s", cmd.Command, response) } 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) - } + assertions.AssertResult(t, err, response, result.Expected, result.ErrorExpected) + } }) } diff --git a/internal/tests/integration/commands/hset_test.go b/internal/tests/integration/commands/hset_test.go index 3f5ef24..0174ffa 100644 --- a/internal/tests/integration/commands/hset_test.go +++ b/internal/tests/integration/commands/hset_test.go @@ -1,9 +1,8 @@ package commands import ( + "server/internal/tests/integration/commands/assertions" "testing" - - "github.com/stretchr/testify/assert" ) func TestHSet(t *testing.T) { @@ -60,16 +59,14 @@ func TestHSet(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) + t.Logf("Error executing command: %s - %v", cmd.Command, err) + } else { + t.Logf("Response for command %s: %s", cmd.Command, response) } 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) - } + assertions.AssertResult(t, err, response, result.Expected, result.ErrorExpected) + } }) }