-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Implement Kafka 0.9 protocol additions #577
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
2bac783
Add new protocol errors with their respective messages.
wvanbergen 1badb8e
Add JoinGroup request and response pair.
wvanbergen b1d40bd
Add Heartbeat request and response pair.
wvanbergen ccec1aa
Add LeaveGroup request and response pair.
wvanbergen 0d36de6
Add SyncGroup request and response pair.
wvanbergen 037310a
Add ListGroups request and response pair.
wvanbergen 7611ea6
Add DescribeGroup request and response pair.
wvanbergen a050648
Register new request type keys in request.go
wvanbergen 9dbdf89
Better assertion failure messages from request_test.
wvanbergen 1621c49
Add tests for all new request types.
wvanbergen 756801d
Add tests for all new response types
wvanbergen 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 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,26 @@ | ||
package sarama | ||
|
||
type DescribeGroupsRequest struct { | ||
Groups []string | ||
} | ||
|
||
func (r *DescribeGroupsRequest) encode(pe packetEncoder) error { | ||
return pe.putStringArray(r.Groups) | ||
} | ||
|
||
func (r *DescribeGroupsRequest) decode(pd packetDecoder) (err error) { | ||
r.Groups, err = pd.getStringArray() | ||
return | ||
} | ||
|
||
func (r *DescribeGroupsRequest) key() int16 { | ||
return 15 | ||
} | ||
|
||
func (r *DescribeGroupsRequest) version() int16 { | ||
return 0 | ||
} | ||
|
||
func (r *DescribeGroupsRequest) AddGroup(group string) { | ||
r.Groups = append(r.Groups, group) | ||
} |
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,34 @@ | ||
package sarama | ||
|
||
import "testing" | ||
|
||
var ( | ||
emptyDescribeGroupsRequest = []byte{0, 0, 0, 0} | ||
|
||
singleDescribeGroupsRequest = []byte{ | ||
0, 0, 0, 1, // 1 group | ||
0, 3, 'f', 'o', 'o', // group name: foo | ||
} | ||
|
||
doubleDescribeGroupsRequest = []byte{ | ||
0, 0, 0, 2, // 2 groups | ||
0, 3, 'f', 'o', 'o', // group name: foo | ||
0, 3, 'b', 'a', 'r', // group name: foo | ||
} | ||
) | ||
|
||
func TestDescribeGroupsRequest(t *testing.T) { | ||
var request *DescribeGroupsRequest | ||
|
||
request = new(DescribeGroupsRequest) | ||
testRequest(t, "no groups", request, emptyDescribeGroupsRequest) | ||
|
||
request = new(DescribeGroupsRequest) | ||
request.AddGroup("foo") | ||
testRequest(t, "one group", request, singleDescribeGroupsRequest) | ||
|
||
request = new(DescribeGroupsRequest) | ||
request.AddGroup("foo") | ||
request.AddGroup("bar") | ||
testRequest(t, "two groups", request, doubleDescribeGroupsRequest) | ||
} |
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,162 @@ | ||
package sarama | ||
|
||
type DescribeGroupsResponse struct { | ||
Groups []*GroupDescription | ||
} | ||
|
||
func (r *DescribeGroupsResponse) encode(pe packetEncoder) error { | ||
if err := pe.putArrayLength(len(r.Groups)); err != nil { | ||
return err | ||
} | ||
|
||
for _, groupDescription := range r.Groups { | ||
if err := groupDescription.encode(pe); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (r *DescribeGroupsResponse) decode(pd packetDecoder) (err error) { | ||
n, err := pd.getArrayLength() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
r.Groups = make([]*GroupDescription, n) | ||
for i := 0; i < n; i++ { | ||
r.Groups[i] = new(GroupDescription) | ||
if err := r.Groups[i].decode(pd); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
type GroupDescription struct { | ||
Err KError | ||
GroupId string | ||
State string | ||
ProtocolType string | ||
Protocol string | ||
Members map[string]*GroupMemberDescription | ||
} | ||
|
||
func (gd *GroupDescription) encode(pe packetEncoder) error { | ||
pe.putInt16(int16(gd.Err)) | ||
|
||
if err := pe.putString(gd.GroupId); err != nil { | ||
return err | ||
} | ||
if err := pe.putString(gd.State); err != nil { | ||
return err | ||
} | ||
if err := pe.putString(gd.ProtocolType); err != nil { | ||
return err | ||
} | ||
if err := pe.putString(gd.Protocol); err != nil { | ||
return err | ||
} | ||
|
||
if err := pe.putArrayLength(len(gd.Members)); err != nil { | ||
return err | ||
} | ||
|
||
for memberId, groupMemberDescription := range gd.Members { | ||
if err := pe.putString(memberId); err != nil { | ||
return err | ||
} | ||
if err := groupMemberDescription.encode(pe); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (gd *GroupDescription) decode(pd packetDecoder) (err error) { | ||
if kerr, err := pd.getInt16(); err != nil { | ||
return err | ||
} else { | ||
gd.Err = KError(kerr) | ||
} | ||
|
||
if gd.GroupId, err = pd.getString(); err != nil { | ||
return | ||
} | ||
if gd.State, err = pd.getString(); err != nil { | ||
return | ||
} | ||
if gd.ProtocolType, err = pd.getString(); err != nil { | ||
return | ||
} | ||
if gd.Protocol, err = pd.getString(); err != nil { | ||
return | ||
} | ||
|
||
n, err := pd.getArrayLength() | ||
if err != nil { | ||
return err | ||
} | ||
if n == 0 { | ||
return nil | ||
} | ||
|
||
gd.Members = make(map[string]*GroupMemberDescription) | ||
for i := 0; i < n; i++ { | ||
memberId, err := pd.getString() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
gd.Members[memberId] = new(GroupMemberDescription) | ||
if err := gd.Members[memberId].decode(pd); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
type GroupMemberDescription struct { | ||
ClientId string | ||
ClientHost string | ||
MemberMetadata []byte | ||
MemberAssignment []byte | ||
} | ||
|
||
func (gmd *GroupMemberDescription) encode(pe packetEncoder) error { | ||
if err := pe.putString(gmd.ClientId); err != nil { | ||
return err | ||
} | ||
if err := pe.putString(gmd.ClientHost); err != nil { | ||
return err | ||
} | ||
if err := pe.putBytes(gmd.MemberMetadata); err != nil { | ||
return err | ||
} | ||
if err := pe.putBytes(gmd.MemberAssignment); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (gmd *GroupMemberDescription) decode(pd packetDecoder) (err error) { | ||
if gmd.ClientId, err = pd.getString(); err != nil { | ||
return | ||
} | ||
if gmd.ClientHost, err = pd.getString(); err != nil { | ||
return | ||
} | ||
if gmd.MemberMetadata, err = pd.getBytes(); err != nil { | ||
return | ||
} | ||
if gmd.MemberAssignment, err = pd.getBytes(); err != nil { | ||
return | ||
} | ||
|
||
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,91 @@ | ||
package sarama | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
var ( | ||
describeGroupsResponseEmpty = []byte{ | ||
0, 0, 0, 0, // no groups | ||
} | ||
|
||
describeGroupsResponsePopulated = []byte{ | ||
0, 0, 0, 2, // 2 groups | ||
|
||
0, 0, // no error | ||
0, 3, 'f', 'o', 'o', // Group ID | ||
0, 3, 'b', 'a', 'r', // State | ||
0, 8, 'c', 'o', 'n', 's', 'u', 'm', 'e', 'r', // ConsumerProtocol type | ||
0, 3, 'b', 'a', 'z', // Protocol name | ||
0, 0, 0, 1, // 1 member | ||
0, 2, 'i', 'd', // Member ID | ||
0, 6, 's', 'a', 'r', 'a', 'm', 'a', // Client ID | ||
0, 9, 'l', 'o', 'c', 'a', 'l', 'h', 'o', 's', 't', // Client Host | ||
0, 0, 0, 3, 0x01, 0x02, 0x03, // MemberMetadata | ||
0, 0, 0, 3, 0x04, 0x05, 0x06, // MemberAssignment | ||
|
||
0, 30, // ErrGroupAuthorizationFailed | ||
0, 0, | ||
0, 0, | ||
0, 0, | ||
0, 0, | ||
0, 0, 0, 0, | ||
} | ||
) | ||
|
||
func TestDescribeGroupsResponse(t *testing.T) { | ||
var response *DescribeGroupsResponse | ||
|
||
response = new(DescribeGroupsResponse) | ||
testDecodable(t, "empty", response, describeGroupsResponseEmpty) | ||
if len(response.Groups) != 0 { | ||
t.Error("Expected no groups") | ||
} | ||
|
||
response = new(DescribeGroupsResponse) | ||
testDecodable(t, "populated", response, describeGroupsResponsePopulated) | ||
if len(response.Groups) != 2 { | ||
t.Error("Expected two groups") | ||
} | ||
|
||
group0 := response.Groups[0] | ||
if group0.Err != ErrNoError { | ||
t.Error("Unxpected groups[0].Err, found", group0.Err) | ||
} | ||
if group0.GroupId != "foo" { | ||
t.Error("Unxpected groups[0].GroupId, found", group0.GroupId) | ||
} | ||
if group0.State != "bar" { | ||
t.Error("Unxpected groups[0].State, found", group0.State) | ||
} | ||
if group0.ProtocolType != "consumer" { | ||
t.Error("Unxpected groups[0].ProtocolType, found", group0.ProtocolType) | ||
} | ||
if group0.Protocol != "baz" { | ||
t.Error("Unxpected groups[0].Protocol, found", group0.Protocol) | ||
} | ||
if len(group0.Members) != 1 { | ||
t.Error("Unxpected groups[0].Members, found", group0.Members) | ||
} | ||
if group0.Members["id"].ClientId != "sarama" { | ||
t.Error("Unxpected groups[0].Members[id].ClientId, found", group0.Members["id"].ClientId) | ||
} | ||
if group0.Members["id"].ClientHost != "localhost" { | ||
t.Error("Unxpected groups[0].Members[id].ClientHost, found", group0.Members["id"].ClientHost) | ||
} | ||
if !reflect.DeepEqual(group0.Members["id"].MemberMetadata, []byte{0x01, 0x02, 0x03}) { | ||
t.Error("Unxpected groups[0].Members[id].MemberMetadata, found", group0.Members["id"].MemberMetadata) | ||
} | ||
if !reflect.DeepEqual(group0.Members["id"].MemberAssignment, []byte{0x04, 0x05, 0x06}) { | ||
t.Error("Unxpected groups[0].Members[id].MemberAssignment, found", group0.Members["id"].MemberAssignment) | ||
} | ||
|
||
group1 := response.Groups[1] | ||
if group1.Err != ErrGroupAuthorizationFailed { | ||
t.Error("Unxpected groups[1].Err, found", group0.Err) | ||
} | ||
if len(group1.Members) != 0 { | ||
t.Error("Unxpected groups[1].Members, found", group0.Members) | ||
} | ||
} |
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
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.
kinda/almost/sorta makes sense for this to be a map keyed by group ID, but not sure if it's worth it at this point
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.
it would make decode rather more complex
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.
I also like that this matches the request: you ask for a slice of groups, you get a slice of group descriptions back.
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.
fair