-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #153 from codecrafters-io/CC-1299-txn
CC-1299: Implement Transactions extension tests
- Loading branch information
Showing
25 changed files
with
3,365 additions
and
219 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package resp_assertions | ||
|
||
import ( | ||
"fmt" | ||
|
||
resp_value "github.com/codecrafters-io/redis-tester/internal/resp/value" | ||
) | ||
|
||
type ErrorAssertion struct { | ||
ExpectedValue string | ||
} | ||
|
||
func NewErrorAssertion(expectedValue string) RESPAssertion { | ||
return ErrorAssertion{ExpectedValue: expectedValue} | ||
} | ||
|
||
func (a ErrorAssertion) Run(value resp_value.Value) error { | ||
if value.Type != resp_value.ERROR { | ||
return fmt.Errorf("Expected error, got %s", value.Type) | ||
} | ||
|
||
if value.Error() != a.ExpectedValue { | ||
return fmt.Errorf("Expected %q, got %q", a.ExpectedValue, value.Error()) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package resp_assertions | ||
|
||
import ( | ||
"fmt" | ||
|
||
resp_value "github.com/codecrafters-io/redis-tester/internal/resp/value" | ||
) | ||
|
||
// OrderedArrayAssertion : Order of the actual and expected values matters. | ||
// All RESP values are accepted as elements in this array. | ||
// We don't alter the ordering. | ||
// For each element in the array, we run the corresponding assertion. | ||
type OrderedArrayAssertion struct { | ||
ExpectedValue []RESPAssertion | ||
} | ||
|
||
func NewOrderedArrayAssertion(expectedValue []RESPAssertion) RESPAssertion { | ||
return OrderedArrayAssertion{ExpectedValue: expectedValue} | ||
} | ||
|
||
func (a OrderedArrayAssertion) Run(value resp_value.Value) error { | ||
if value.Type != resp_value.ARRAY { | ||
return fmt.Errorf("Expected an array, got %s", value.Type) | ||
} | ||
|
||
if len(value.Array()) != len(a.ExpectedValue) { | ||
return fmt.Errorf("Expected %d elements in array, got %d (%s)", len(a.ExpectedValue), len(value.Array()), value.FormattedString()) | ||
} | ||
|
||
for i, assertion := range a.ExpectedValue { | ||
actualElement := value.Array()[i] | ||
|
||
if err := assertion.Run(actualElement); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package test_cases | ||
|
||
import ( | ||
"fmt" | ||
|
||
resp_client "github.com/codecrafters-io/redis-tester/internal/resp/connection" | ||
"github.com/codecrafters-io/redis-tester/internal/resp_assertions" | ||
"github.com/codecrafters-io/tester-utils/logger" | ||
) | ||
|
||
// MultiCommandTestCase is a concise & easier way to define & run multiple SendCommandTestCase | ||
type MultiCommandTestCase struct { | ||
Commands [][]string | ||
Assertions []resp_assertions.RESPAssertion | ||
} | ||
|
||
func (t *MultiCommandTestCase) RunAll(client *resp_client.RespConnection, logger *logger.Logger) error { | ||
if len(t.Assertions) != len(t.Commands) { | ||
return fmt.Errorf("CodeCrafters internal error. Number of commands and assertions should be equal in MultiCommandTestCase") | ||
} | ||
|
||
for i, command := range t.Commands { | ||
setCommandTestCase := SendCommandTestCase{ | ||
Command: command[0], | ||
Args: command[1:], | ||
Assertion: t.Assertions[i], | ||
} | ||
|
||
if err := setCommandTestCase.Run(client, logger); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package test_cases | ||
|
||
import ( | ||
resp_client "github.com/codecrafters-io/redis-tester/internal/resp/connection" | ||
"github.com/codecrafters-io/redis-tester/internal/resp_assertions" | ||
"github.com/codecrafters-io/tester-utils/logger" | ||
) | ||
|
||
// TransactionTestCase is a test case where we initiate a transaction by sending "MULTI" command | ||
// Send a series of commands to the server expected back "QUEUED" for each command | ||
// Finally send "EXEC" command and expect the response to be the same as ExpectedResponseArray | ||
// | ||
// RunAll will run all the steps in the Transaction execution. Alternatively, you | ||
// can run each step individually. | ||
type TransactionTestCase struct { | ||
// All the CommandQueue will be sent in order to client | ||
// And a string "QUEUED" will be expected | ||
CommandQueue [][]string | ||
|
||
// After queueing all the commands, | ||
// if "EXEC" is sent (based on which function is called) | ||
// The elements in the response array are asserted based on the | ||
// assertions in the ExpectedResponseArray | ||
ExpectedResponseArray []resp_assertions.RESPAssertion | ||
} | ||
|
||
func (t TransactionTestCase) RunAll(client *resp_client.RespConnection, logger *logger.Logger) error { | ||
if err := t.RunMulti(client, logger); err != nil { | ||
return err | ||
} | ||
|
||
if err := t.RunQueueAll(client, logger); err != nil { | ||
return err | ||
} | ||
|
||
if err := t.RunExec(client, logger); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (t TransactionTestCase) RunWithoutExec(client *resp_client.RespConnection, logger *logger.Logger) error { | ||
if err := t.RunMulti(client, logger); err != nil { | ||
return err | ||
} | ||
|
||
if err := t.RunQueueAll(client, logger); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (t TransactionTestCase) RunMulti(client *resp_client.RespConnection, logger *logger.Logger) error { | ||
commandTest := SendCommandTestCase{ | ||
Command: "MULTI", | ||
Args: []string{}, | ||
Assertion: resp_assertions.NewStringAssertion("OK"), | ||
} | ||
|
||
return commandTest.Run(client, logger) | ||
} | ||
|
||
func (t TransactionTestCase) RunQueueAll(client *resp_client.RespConnection, logger *logger.Logger) error { | ||
for i, v := range t.CommandQueue { | ||
logger.Debugf("Sending command: #%d/#%d", i+1, len(t.CommandQueue)) | ||
commandTest := SendCommandTestCase{ | ||
Command: v[0], | ||
Args: v[1:], | ||
Assertion: resp_assertions.NewStringAssertion("QUEUED"), | ||
} | ||
if err := commandTest.Run(client, logger); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (t TransactionTestCase) RunExec(client *resp_client.RespConnection, logger *logger.Logger) error { | ||
setCommandTestCase := SendCommandTestCase{ | ||
Command: "EXEC", | ||
Args: []string{}, | ||
Assertion: resp_assertions.NewOrderedArrayAssertion(t.ExpectedResponseArray), | ||
} | ||
|
||
return setCommandTestCase.Run(client, logger) | ||
} |
Oops, something went wrong.