generated from codecrafters-io/tester-template
-
Notifications
You must be signed in to change notification settings - Fork 2
Refactor base stages #92
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
36 commits
Select commit
Hold shift + click to select a range
0977102
Rename decoder -> decoder_legacy
UdeshyaDhungana 2e38b0d
Suffix modules with *_legacy
UdeshyaDhungana a492573
Rename all usages
UdeshyaDhungana 9d07a5e
Rename all remaining usages
UdeshyaDhungana be0cb21
Rename errors -> errors_legacy
UdeshyaDhungana a7ba1d5
assertions package is now legacy
UdeshyaDhungana a18ba77
Add new decoder and errors package
UdeshyaDhungana c3f9b6d
Rename builder to builder_legacy
UdeshyaDhungana 9a570ff
Rename builder_legacy usages
UdeshyaDhungana 27f017f
Merge branch 'rename-modules' into temp
UdeshyaDhungana c8d1f04
migrate upto stage 4
UdeshyaDhungana f292d88
Add remaining files
UdeshyaDhungana 3969d77
client and interface moved to legacy
UdeshyaDhungana 6d88217
Resolve merge conflict
UdeshyaDhungana 10411d7
move encoder to legacy
UdeshyaDhungana 830cd46
Merge branch 'rename-modules' into temp
UdeshyaDhungana 2bc71fa
serializer -> serializer_legacy
UdeshyaDhungana 8c8175b
Resolve merge conflict
UdeshyaDhungana 9171cb6
First round of refactor
UdeshyaDhungana bafa2da
Apply suggested fixes
UdeshyaDhungana 88869fd
Remove the usage of serializer_legacy in base stages
UdeshyaDhungana 3c4cecf
Minor refactor
UdeshyaDhungana 70533ee
Refactor files manager
UdeshyaDhungana cf33239
Encoder interface changed
UdeshyaDhungana 6a52ba2
Remove logger and indentation in ApiVersionsResponseBody.Decode()
UdeshyaDhungana 7662386
Change decoder printing format and refactor api_versions_response.go
UdeshyaDhungana 8bc159e
Refactor and regenerate fixtures
UdeshyaDhungana 8b662c7
Refactor base stages and dependencies
UdeshyaDhungana 97cf7fa
Refactor decoder
UdeshyaDhungana 17468a4
Refactor decoder
UdeshyaDhungana ac4ba7e
Remove files manager for refactor-base-stages
UdeshyaDhungana d9bf369
Reove printing log files details to CLI in base stages
UdeshyaDhungana 0d6c84c
Merge with main
UdeshyaDhungana b488f96
Add missing files after git merge
UdeshyaDhungana 76723a5
Minor decoder refactor
UdeshyaDhungana 391be3d
CI: Re-record Fixtures
UdeshyaDhungana File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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,106 @@ | ||
package assertions | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/codecrafters-io/kafka-tester/protocol/kafkaapi" | ||
"github.com/codecrafters-io/tester-utils/logger" | ||
) | ||
|
||
var apiKeyNames = map[int16]string{ | ||
1: "FETCH", | ||
18: "API_VERSIONS", | ||
75: "DESCRIBE_TOPIC_PARTITIONS", | ||
} | ||
|
||
var errorCodes = map[int]string{ | ||
0: "NO_ERROR", | ||
3: "UNKNOWN_TOPIC_OR_PARTITION", | ||
35: "UNSUPPORTED_VERSION", | ||
100: "UNKNOWN_TOPIC_ID", | ||
} | ||
|
||
type ApiVersionsResponseAssertion struct { | ||
ActualValue kafkaapi.ApiVersionsResponse | ||
ExpectedValue kafkaapi.ApiVersionsResponse | ||
} | ||
|
||
func NewApiVersionsResponseAssertion(actualValue kafkaapi.ApiVersionsResponse, expectedValue kafkaapi.ApiVersionsResponse) *ApiVersionsResponseAssertion { | ||
return &ApiVersionsResponseAssertion{ | ||
ActualValue: actualValue, | ||
ExpectedValue: expectedValue, | ||
} | ||
} | ||
|
||
func (a *ApiVersionsResponseAssertion) assertBody(logger *logger.Logger) error { | ||
expectedErrorCodeName, ok := errorCodes[int(a.ExpectedValue.Body.ErrorCode)] | ||
|
||
if !ok { | ||
panic(fmt.Sprintf("CodeCrafters Internal Error: Expected %d to be in errorCodes map", a.ExpectedValue.Body.ErrorCode)) | ||
} | ||
|
||
if a.ActualValue.Body.ErrorCode != a.ExpectedValue.Body.ErrorCode { | ||
return fmt.Errorf("Expected ErrorCode to be %d (%s), got %d", a.ExpectedValue.Body.ErrorCode, expectedErrorCodeName, a.ActualValue.Body.ErrorCode) | ||
} | ||
|
||
logger.Successf("✓ ErrorCode: %d (%s)", a.ActualValue.Body.ErrorCode, expectedErrorCodeName) | ||
|
||
if err := a.assertAPIKeysArray(logger); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (a *ApiVersionsResponseAssertion) assertAPIKeysArray(logger *logger.Logger) error { | ||
if len(a.ActualValue.Body.ApiKeys) < len(a.ExpectedValue.Body.ApiKeys) { | ||
return fmt.Errorf("Expected API keys array to include atleast %d keys, got %d", len(a.ExpectedValue.Body.ApiKeys), len(a.ActualValue.Body.ApiKeys)) | ||
} | ||
|
||
logger.Successf("✓ API keys array length: %d", len(a.ActualValue.Body.ApiKeys)) | ||
|
||
for _, expectedApiVersionKey := range a.ExpectedValue.Body.ApiKeys { | ||
found := false | ||
|
||
for _, actualApiVersionKey := range a.ActualValue.Body.ApiKeys { | ||
if actualApiVersionKey.ApiKey == expectedApiVersionKey.ApiKey { | ||
found = true | ||
|
||
if actualApiVersionKey.MinVersion > expectedApiVersionKey.MaxVersion { | ||
return fmt.Errorf("Expected min version %v to be < max version %v for %s", actualApiVersionKey.MinVersion, expectedApiVersionKey.MaxVersion, apiKeyNames[expectedApiVersionKey.ApiKey]) | ||
} | ||
|
||
// anything above or equal to expected minVersion is fine | ||
if actualApiVersionKey.MinVersion < expectedApiVersionKey.MinVersion { | ||
return fmt.Errorf("Expected API version %v to be supported for %s, got %v", expectedApiVersionKey.MinVersion, apiKeyNames[expectedApiVersionKey.ApiKey], actualApiVersionKey.MinVersion) | ||
} | ||
|
||
logger.Successf("✓ MinVersion for %s is <= %v & >= %v", apiKeyNames[expectedApiVersionKey.ApiKey], expectedApiVersionKey.MaxVersion, expectedApiVersionKey.MinVersion) | ||
|
||
if actualApiVersionKey.MaxVersion < expectedApiVersionKey.MaxVersion { | ||
return fmt.Errorf("Expected API version %v to be supported for %s, got %v", expectedApiVersionKey.MaxVersion, apiKeyNames[expectedApiVersionKey.ApiKey], actualApiVersionKey.MaxVersion) | ||
} | ||
|
||
logger.Successf("✓ MaxVersion for %s is >= %v", apiKeyNames[expectedApiVersionKey.ApiKey], expectedApiVersionKey.MaxVersion) | ||
} | ||
} | ||
|
||
if !found { | ||
return fmt.Errorf("Expected APIVersionsResponseKey array to include API key %d (%s)", expectedApiVersionKey.ApiKey, apiKeyNames[expectedApiVersionKey.ApiKey]) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (a *ApiVersionsResponseAssertion) Run(logger *logger.Logger) error { | ||
if err := NewResponseHeaderAssertion(a.ActualValue.Header, a.ExpectedValue.Header).Run(logger); err != nil { | ||
return err | ||
} | ||
|
||
if err := a.assertBody(logger); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
This file contains hidden or 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,34 @@ | ||
package assertions | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/codecrafters-io/kafka-tester/protocol/kafkaapi/headers" | ||
"github.com/codecrafters-io/tester-utils/logger" | ||
) | ||
|
||
type ResponseHeaderAssertion struct { | ||
ActualValue headers.ResponseHeader | ||
ExpectedValue headers.ResponseHeader | ||
} | ||
|
||
func NewResponseHeaderAssertion(actualValue headers.ResponseHeader, expectedValue headers.ResponseHeader) *ResponseHeaderAssertion { | ||
return &ResponseHeaderAssertion{ | ||
ActualValue: actualValue, | ||
ExpectedValue: expectedValue, | ||
} | ||
} | ||
|
||
func (a *ResponseHeaderAssertion) assertCorrelationId(logger *logger.Logger) error { | ||
if a.ActualValue.CorrelationId != a.ExpectedValue.CorrelationId { | ||
return fmt.Errorf("Expected correlation_id to be %d, got %d", a.ExpectedValue.CorrelationId, a.ActualValue.CorrelationId) | ||
} | ||
|
||
logger.Successf("✓ correlation_id: %v", a.ActualValue.CorrelationId) | ||
|
||
return nil | ||
} | ||
|
||
func (a *ResponseHeaderAssertion) Run(logger *logger.Logger) error { | ||
return a.assertCorrelationId(logger) | ||
} |
This file contains hidden or 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 hidden or 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 |
---|---|---|
|
@@ -3,45 +3,42 @@ package internal | |
import ( | ||
"fmt" | ||
|
||
"github.com/codecrafters-io/tester-utils/logger" | ||
|
||
"github.com/codecrafters-io/kafka-tester/internal/kafka_executable" | ||
"github.com/codecrafters-io/kafka-tester/protocol" | ||
"github.com/codecrafters-io/kafka-tester/protocol/builder_legacy" | ||
"github.com/codecrafters-io/kafka-tester/protocol/decoder_legacy" | ||
"github.com/codecrafters-io/kafka-tester/protocol/errors_legacy" | ||
"github.com/codecrafters-io/kafka-tester/protocol/kafka_client_legacy" | ||
"github.com/codecrafters-io/kafka-tester/protocol/kafkaapi_legacy" | ||
"github.com/codecrafters-io/kafka-tester/protocol/builder" | ||
"github.com/codecrafters-io/kafka-tester/protocol/decoder" | ||
"github.com/codecrafters-io/kafka-tester/protocol/kafka_client" | ||
"github.com/codecrafters-io/kafka-tester/protocol/kafkaapi" | ||
"github.com/codecrafters-io/kafka-tester/protocol/serializer_legacy" | ||
"github.com/codecrafters-io/kafka-tester/protocol/utils" | ||
"github.com/codecrafters-io/tester-utils/logger" | ||
"github.com/codecrafters-io/tester-utils/test_case_harness" | ||
) | ||
|
||
func testCorrelationId(stageHarness *test_case_harness.TestCaseHarness) error { | ||
b := kafka_executable.NewKafkaExecutable(stageHarness) | ||
err := serializer_legacy.GenerateLogDirs(logger.GetQuietLogger(""), true) | ||
if err != nil { | ||
stageLogger := stageHarness.Logger | ||
|
||
if err := serializer_legacy.GenerateLogDirs(logger.GetQuietLogger(""), true); err != nil { | ||
return err | ||
} | ||
|
||
stageLogger := stageHarness.Logger | ||
b := kafka_executable.NewKafkaExecutable(stageHarness) | ||
|
||
if err := b.Run(); err != nil { | ||
return err | ||
} | ||
|
||
client := kafka_client_legacy.NewClient("localhost:9092") | ||
client := kafka_client.NewClient("localhost:9092") | ||
|
||
if err := client.ConnectWithRetries(b, stageLogger); err != nil { | ||
return err | ||
} | ||
defer func(client *kafka_client_legacy.Client) { | ||
_ = client.Close() | ||
}(client) | ||
|
||
defer client.Close() | ||
correlationId := getRandomCorrelationId() | ||
|
||
request := kafkaapi_legacy.ApiVersionsRequest{ | ||
Header: builder_legacy.NewRequestHeaderBuilder().BuildApiVersionsRequestHeader(correlationId), | ||
Body: kafkaapi_legacy.ApiVersionsRequestBody{ | ||
request := kafkaapi.ApiVersionsRequest{ | ||
Header: builder.NewRequestHeaderBuilder().BuildApiVersionsRequestHeader(correlationId), | ||
Body: kafkaapi.ApiVersionsRequestBody{ | ||
Version: 4, | ||
ClientSoftwareName: "kafka-cli", | ||
ClientSoftwareVersion: "0.1", | ||
|
@@ -51,42 +48,35 @@ func testCorrelationId(stageHarness *test_case_harness.TestCaseHarness) error { | |
message := request.Encode() | ||
stageLogger.Infof("Sending \"ApiVersions\" (version: %v) request (Correlation id: %v)", request.Header.ApiVersion, request.Header.CorrelationId) | ||
stageLogger.Debugf("Hexdump of sent \"ApiVersions\" request: \n%v\n", utils.GetFormattedHexdump(message)) | ||
err := client.Send(message) | ||
|
||
err = client.Send(message) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
response, err := client.ReceiveRaw() | ||
|
||
if err != nil { | ||
return err | ||
} | ||
stageLogger.Debugf("Hexdump of received \"ApiVersions\" response: \n%v\n", utils.GetFormattedHexdump(response)) | ||
|
||
decoder := decoder_legacy.Decoder{} | ||
decoder.Init(response) | ||
stageLogger.UpdateLastSecondaryPrefix("Decoder") | ||
stageLogger.Debugf("Hexdump of received \"ApiVersions\" response: \n%v\n", utils.GetFormattedHexdump(response)) | ||
decoder := decoder.NewDecoder(response, stageLogger) | ||
decoder.BeginSubSection("response") | ||
_, err = decoder.ReadInt32("message_length") | ||
|
||
stageLogger.Debugf("- .Response") | ||
messageLength, err := decoder.GetInt32() | ||
if err != nil { | ||
if decodingErr, ok := err.(*errors_legacy.PacketDecodingError); ok { | ||
err = decodingErr.WithAddedContext("message length").WithAddedContext("response") | ||
return decoder.FormatDetailedError(err.Error()) | ||
} | ||
return err | ||
} | ||
protocol.LogWithIndentation(stageLogger, 1, "- .message_length (%d)", messageLength) | ||
|
||
stageLogger.Debugf("- .response_header") | ||
responseCorrelationId, err := decoder.GetInt32() | ||
decoder.BeginSubSection("response_header") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Decoder Missing End Calls Causes Log Formatting IssuesThe new decoder's Additional Locations (2) |
||
|
||
responseCorrelationId, err := decoder.ReadInt32("correlation_id") | ||
|
||
if err != nil { | ||
if decodingErr, ok := err.(*errors_legacy.PacketDecodingError); ok { | ||
err = decodingErr.WithAddedContext("correlation_id").WithAddedContext("response") | ||
return decoder.FormatDetailedError(err.Error()) | ||
} | ||
return err | ||
} | ||
protocol.LogWithIndentation(stageLogger, 1, "- .correlation_id (%d)", responseCorrelationId) | ||
|
||
stageLogger.ResetSecondaryPrefixes() | ||
|
||
if responseCorrelationId != correlationId { | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Decoder Indentation Leak
The
decoder.BeginSubSection("response_header")
call instage_2.go
,stage_3.go
, andstage_4.go
lacks a matchingEndCurrentSubSection()
. This leaves the decoder's log indentation permanently increased for any subsequent logging operations.Additional Locations (2)
internal/stage_3.go#L71-L72
internal/stage_4.go#L72-L73