|
|
|
@ -5,14 +5,14 @@ import ( |
|
|
|
"net" |
|
|
|
"testing" |
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/mq/kafka/consumer" |
|
|
|
) |
|
|
|
|
|
|
|
func TestHandler_handleHeartbeat(t *testing.T) { |
|
|
|
h := NewHandler() |
|
|
|
h := NewTestHandler() |
|
|
|
defer h.Close() |
|
|
|
|
|
|
|
|
|
|
|
// Create a consumer group with a stable member
|
|
|
|
group := h.groupCoordinator.GetOrCreateGroup("test-group") |
|
|
|
group.Mu.Lock() |
|
|
|
@ -24,33 +24,33 @@ func TestHandler_handleHeartbeat(t *testing.T) { |
|
|
|
LastHeartbeat: time.Now().Add(-5 * time.Second), // 5 seconds ago
|
|
|
|
} |
|
|
|
group.Mu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
// Create a basic heartbeat request
|
|
|
|
requestBody := createHeartbeatRequestBody("test-group", 1, "member1") |
|
|
|
|
|
|
|
|
|
|
|
correlationID := uint32(123) |
|
|
|
response, err := h.handleHeartbeat(correlationID, requestBody) |
|
|
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
t.Fatalf("handleHeartbeat failed: %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if len(response) < 8 { |
|
|
|
t.Fatalf("response too short: %d bytes", len(response)) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Check correlation ID in response
|
|
|
|
respCorrelationID := binary.BigEndian.Uint32(response[0:4]) |
|
|
|
if respCorrelationID != correlationID { |
|
|
|
t.Errorf("expected correlation ID %d, got %d", correlationID, respCorrelationID) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Check error code (should be ErrorCodeNone for successful heartbeat)
|
|
|
|
errorCode := int16(binary.BigEndian.Uint16(response[4:6])) |
|
|
|
if errorCode != ErrorCodeNone { |
|
|
|
t.Errorf("expected error code %d, got %d", ErrorCodeNone, errorCode) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Verify heartbeat timestamp was updated
|
|
|
|
group.Mu.RLock() |
|
|
|
member := group.Members["member1"] |
|
|
|
@ -61,9 +61,9 @@ func TestHandler_handleHeartbeat(t *testing.T) { |
|
|
|
} |
|
|
|
|
|
|
|
func TestHandler_handleHeartbeat_RebalanceInProgress(t *testing.T) { |
|
|
|
h := NewHandler() |
|
|
|
h := NewTestHandler() |
|
|
|
defer h.Close() |
|
|
|
|
|
|
|
|
|
|
|
// Create a consumer group in rebalancing state
|
|
|
|
group := h.groupCoordinator.GetOrCreateGroup("test-group") |
|
|
|
group.Mu.Lock() |
|
|
|
@ -75,20 +75,20 @@ func TestHandler_handleHeartbeat_RebalanceInProgress(t *testing.T) { |
|
|
|
LastHeartbeat: time.Now().Add(-5 * time.Second), |
|
|
|
} |
|
|
|
group.Mu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
requestBody := createHeartbeatRequestBody("test-group", 1, "member1") |
|
|
|
|
|
|
|
|
|
|
|
correlationID := uint32(124) |
|
|
|
response, err := h.handleHeartbeat(correlationID, requestBody) |
|
|
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
t.Fatalf("handleHeartbeat failed: %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if len(response) < 8 { |
|
|
|
t.Fatalf("response too short: %d bytes", len(response)) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Should return ErrorCodeRebalanceInProgress
|
|
|
|
errorCode := int16(binary.BigEndian.Uint16(response[4:6])) |
|
|
|
if errorCode != ErrorCodeRebalanceInProgress { |
|
|
|
@ -97,9 +97,9 @@ func TestHandler_handleHeartbeat_RebalanceInProgress(t *testing.T) { |
|
|
|
} |
|
|
|
|
|
|
|
func TestHandler_handleHeartbeat_WrongGeneration(t *testing.T) { |
|
|
|
h := NewHandler() |
|
|
|
h := NewTestHandler() |
|
|
|
defer h.Close() |
|
|
|
|
|
|
|
|
|
|
|
// Create a consumer group with generation 2
|
|
|
|
group := h.groupCoordinator.GetOrCreateGroup("test-group") |
|
|
|
group.Mu.Lock() |
|
|
|
@ -111,17 +111,17 @@ func TestHandler_handleHeartbeat_WrongGeneration(t *testing.T) { |
|
|
|
LastHeartbeat: time.Now().Add(-5 * time.Second), |
|
|
|
} |
|
|
|
group.Mu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
// Send heartbeat with wrong generation (1 instead of 2)
|
|
|
|
requestBody := createHeartbeatRequestBody("test-group", 1, "member1") |
|
|
|
|
|
|
|
|
|
|
|
correlationID := uint32(125) |
|
|
|
response, err := h.handleHeartbeat(correlationID, requestBody) |
|
|
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
t.Fatalf("handleHeartbeat failed: %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Should return ErrorCodeIllegalGeneration
|
|
|
|
errorCode := int16(binary.BigEndian.Uint16(response[4:6])) |
|
|
|
if errorCode != ErrorCodeIllegalGeneration { |
|
|
|
@ -130,9 +130,9 @@ func TestHandler_handleHeartbeat_WrongGeneration(t *testing.T) { |
|
|
|
} |
|
|
|
|
|
|
|
func TestHandler_handleHeartbeat_UnknownMember(t *testing.T) { |
|
|
|
h := NewHandler() |
|
|
|
h := NewTestHandler() |
|
|
|
defer h.Close() |
|
|
|
|
|
|
|
|
|
|
|
// Create a consumer group without the requested member
|
|
|
|
group := h.groupCoordinator.GetOrCreateGroup("test-group") |
|
|
|
group.Mu.Lock() |
|
|
|
@ -140,16 +140,16 @@ func TestHandler_handleHeartbeat_UnknownMember(t *testing.T) { |
|
|
|
group.Generation = 1 |
|
|
|
// No members in group
|
|
|
|
group.Mu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
requestBody := createHeartbeatRequestBody("test-group", 1, "unknown-member") |
|
|
|
|
|
|
|
|
|
|
|
correlationID := uint32(126) |
|
|
|
response, err := h.handleHeartbeat(correlationID, requestBody) |
|
|
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
t.Fatalf("handleHeartbeat failed: %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Should return ErrorCodeUnknownMemberID
|
|
|
|
errorCode := int16(binary.BigEndian.Uint16(response[4:6])) |
|
|
|
if errorCode != ErrorCodeUnknownMemberID { |
|
|
|
@ -158,9 +158,9 @@ func TestHandler_handleHeartbeat_UnknownMember(t *testing.T) { |
|
|
|
} |
|
|
|
|
|
|
|
func TestHandler_handleLeaveGroup(t *testing.T) { |
|
|
|
h := NewHandler() |
|
|
|
h := NewTestHandler() |
|
|
|
defer h.Close() |
|
|
|
|
|
|
|
|
|
|
|
// Create a consumer group with multiple members
|
|
|
|
group := h.groupCoordinator.GetOrCreateGroup("test-group") |
|
|
|
group.Mu.Lock() |
|
|
|
@ -182,58 +182,58 @@ func TestHandler_handleLeaveGroup(t *testing.T) { |
|
|
|
"topic2": true, |
|
|
|
} |
|
|
|
group.Mu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
// Create a leave group request
|
|
|
|
requestBody := createLeaveGroupRequestBody("test-group", "member2") |
|
|
|
|
|
|
|
|
|
|
|
correlationID := uint32(127) |
|
|
|
response, err := h.handleLeaveGroup(correlationID, requestBody) |
|
|
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
t.Fatalf("handleLeaveGroup failed: %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if len(response) < 8 { |
|
|
|
t.Fatalf("response too short: %d bytes", len(response)) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Check correlation ID in response
|
|
|
|
respCorrelationID := binary.BigEndian.Uint32(response[0:4]) |
|
|
|
if respCorrelationID != correlationID { |
|
|
|
t.Errorf("expected correlation ID %d, got %d", correlationID, respCorrelationID) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Check error code (should be ErrorCodeNone for successful leave)
|
|
|
|
errorCode := int16(binary.BigEndian.Uint16(response[4:6])) |
|
|
|
if errorCode != ErrorCodeNone { |
|
|
|
t.Errorf("expected error code %d, got %d", ErrorCodeNone, errorCode) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Verify member was removed and group state updated
|
|
|
|
group.Mu.RLock() |
|
|
|
if _, exists := group.Members["member2"]; exists { |
|
|
|
t.Error("member2 should have been removed from group") |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if len(group.Members) != 1 { |
|
|
|
t.Errorf("expected 1 remaining member, got %d", len(group.Members)) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Group should be in rebalancing state
|
|
|
|
if group.State != consumer.GroupStatePreparingRebalance { |
|
|
|
t.Errorf("expected group state PreparingRebalance, got %s", group.State) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Generation should be incremented
|
|
|
|
if group.Generation != 2 { |
|
|
|
t.Errorf("expected generation 2, got %d", group.Generation) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Subscribed topics should be updated (only topic1 remains)
|
|
|
|
if len(group.SubscribedTopics) != 1 || !group.SubscribedTopics["topic1"] { |
|
|
|
t.Error("group subscribed topics were not updated correctly") |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if group.SubscribedTopics["topic2"] { |
|
|
|
t.Error("topic2 should have been removed from subscribed topics") |
|
|
|
} |
|
|
|
@ -241,9 +241,9 @@ func TestHandler_handleLeaveGroup(t *testing.T) { |
|
|
|
} |
|
|
|
|
|
|
|
func TestHandler_handleLeaveGroup_LastMember(t *testing.T) { |
|
|
|
h := NewHandler() |
|
|
|
h := NewTestHandler() |
|
|
|
defer h.Close() |
|
|
|
|
|
|
|
|
|
|
|
// Create a consumer group with only one member
|
|
|
|
group := h.groupCoordinator.GetOrCreateGroup("test-group") |
|
|
|
group.Mu.Lock() |
|
|
|
@ -256,36 +256,36 @@ func TestHandler_handleLeaveGroup_LastMember(t *testing.T) { |
|
|
|
Subscription: []string{"topic1"}, |
|
|
|
} |
|
|
|
group.Mu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
requestBody := createLeaveGroupRequestBody("test-group", "member1") |
|
|
|
|
|
|
|
|
|
|
|
correlationID := uint32(128) |
|
|
|
response, err := h.handleLeaveGroup(correlationID, requestBody) |
|
|
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
t.Fatalf("handleLeaveGroup failed: %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Check error code
|
|
|
|
errorCode := int16(binary.BigEndian.Uint16(response[4:6])) |
|
|
|
if errorCode != ErrorCodeNone { |
|
|
|
t.Errorf("expected error code %d, got %d", ErrorCodeNone, errorCode) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Verify group became empty
|
|
|
|
group.Mu.RLock() |
|
|
|
if len(group.Members) != 0 { |
|
|
|
t.Errorf("expected 0 members, got %d", len(group.Members)) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if group.State != consumer.GroupStateEmpty { |
|
|
|
t.Errorf("expected group state Empty, got %s", group.State) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if group.Leader != "" { |
|
|
|
t.Errorf("expected empty leader, got %s", group.Leader) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if group.Generation != 2 { |
|
|
|
t.Errorf("expected generation 2, got %d", group.Generation) |
|
|
|
} |
|
|
|
@ -293,9 +293,9 @@ func TestHandler_handleLeaveGroup_LastMember(t *testing.T) { |
|
|
|
} |
|
|
|
|
|
|
|
func TestHandler_handleLeaveGroup_LeaderLeaves(t *testing.T) { |
|
|
|
h := NewHandler() |
|
|
|
h := NewTestHandler() |
|
|
|
defer h.Close() |
|
|
|
|
|
|
|
|
|
|
|
// Create a consumer group where the leader is leaving
|
|
|
|
group := h.groupCoordinator.GetOrCreateGroup("test-group") |
|
|
|
group.Mu.Lock() |
|
|
|
@ -311,26 +311,26 @@ func TestHandler_handleLeaveGroup_LeaderLeaves(t *testing.T) { |
|
|
|
State: consumer.MemberStateStable, |
|
|
|
} |
|
|
|
group.Mu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
requestBody := createLeaveGroupRequestBody("test-group", "leader-member") |
|
|
|
|
|
|
|
|
|
|
|
correlationID := uint32(129) |
|
|
|
_, err := h.handleLeaveGroup(correlationID, requestBody) |
|
|
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
t.Fatalf("handleLeaveGroup failed: %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Verify leader was changed
|
|
|
|
group.Mu.RLock() |
|
|
|
if group.Leader == "leader-member" { |
|
|
|
t.Error("leader should have been changed after leader left") |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if group.Leader != "other-member" { |
|
|
|
t.Errorf("expected new leader to be 'other-member', got '%s'", group.Leader) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if len(group.Members) != 1 { |
|
|
|
t.Errorf("expected 1 remaining member, got %d", len(group.Members)) |
|
|
|
} |
|
|
|
@ -338,70 +338,70 @@ func TestHandler_handleLeaveGroup_LeaderLeaves(t *testing.T) { |
|
|
|
} |
|
|
|
|
|
|
|
func TestHandler_parseHeartbeatRequest(t *testing.T) { |
|
|
|
h := NewHandler() |
|
|
|
h := NewTestHandler() |
|
|
|
defer h.Close() |
|
|
|
|
|
|
|
|
|
|
|
requestBody := createHeartbeatRequestBody("test-group", 1, "member1") |
|
|
|
|
|
|
|
|
|
|
|
request, err := h.parseHeartbeatRequest(requestBody) |
|
|
|
if err != nil { |
|
|
|
t.Fatalf("parseHeartbeatRequest failed: %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if request.GroupID != "test-group" { |
|
|
|
t.Errorf("expected group ID 'test-group', got '%s'", request.GroupID) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if request.GenerationID != 1 { |
|
|
|
t.Errorf("expected generation ID 1, got %d", request.GenerationID) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if request.MemberID != "member1" { |
|
|
|
t.Errorf("expected member ID 'member1', got '%s'", request.MemberID) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func TestHandler_parseLeaveGroupRequest(t *testing.T) { |
|
|
|
h := NewHandler() |
|
|
|
h := NewTestHandler() |
|
|
|
defer h.Close() |
|
|
|
|
|
|
|
|
|
|
|
requestBody := createLeaveGroupRequestBody("test-group", "member1") |
|
|
|
|
|
|
|
|
|
|
|
request, err := h.parseLeaveGroupRequest(requestBody) |
|
|
|
if err != nil { |
|
|
|
t.Fatalf("parseLeaveGroupRequest failed: %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if request.GroupID != "test-group" { |
|
|
|
t.Errorf("expected group ID 'test-group', got '%s'", request.GroupID) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if request.MemberID != "member1" { |
|
|
|
t.Errorf("expected member ID 'member1', got '%s'", request.MemberID) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func TestHandler_buildHeartbeatResponse(t *testing.T) { |
|
|
|
h := NewHandler() |
|
|
|
h := NewTestHandler() |
|
|
|
defer h.Close() |
|
|
|
|
|
|
|
|
|
|
|
response := HeartbeatResponse{ |
|
|
|
CorrelationID: 123, |
|
|
|
ErrorCode: ErrorCodeRebalanceInProgress, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
responseBytes := h.buildHeartbeatResponse(response) |
|
|
|
|
|
|
|
|
|
|
|
if len(responseBytes) != 10 { // 4 + 2 + 4 bytes
|
|
|
|
t.Fatalf("expected response length 10, got %d", len(responseBytes)) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Check correlation ID
|
|
|
|
correlationID := binary.BigEndian.Uint32(responseBytes[0:4]) |
|
|
|
if correlationID != 123 { |
|
|
|
t.Errorf("expected correlation ID 123, got %d", correlationID) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Check error code
|
|
|
|
errorCode := int16(binary.BigEndian.Uint16(responseBytes[4:6])) |
|
|
|
if errorCode != ErrorCodeRebalanceInProgress { |
|
|
|
@ -410,9 +410,9 @@ func TestHandler_buildHeartbeatResponse(t *testing.T) { |
|
|
|
} |
|
|
|
|
|
|
|
func TestHandler_buildLeaveGroupResponse(t *testing.T) { |
|
|
|
h := NewHandler() |
|
|
|
h := NewTestHandler() |
|
|
|
defer h.Close() |
|
|
|
|
|
|
|
|
|
|
|
response := LeaveGroupResponse{ |
|
|
|
CorrelationID: 124, |
|
|
|
ErrorCode: ErrorCodeNone, |
|
|
|
@ -424,19 +424,19 @@ func TestHandler_buildLeaveGroupResponse(t *testing.T) { |
|
|
|
}, |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
responseBytes := h.buildLeaveGroupResponse(response) |
|
|
|
|
|
|
|
|
|
|
|
if len(responseBytes) < 16 { |
|
|
|
t.Fatalf("response too short: %d bytes", len(responseBytes)) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Check correlation ID
|
|
|
|
correlationID := binary.BigEndian.Uint32(responseBytes[0:4]) |
|
|
|
if correlationID != 124 { |
|
|
|
t.Errorf("expected correlation ID 124, got %d", correlationID) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Check error code
|
|
|
|
errorCode := int16(binary.BigEndian.Uint16(responseBytes[4:6])) |
|
|
|
if errorCode != ErrorCodeNone { |
|
|
|
@ -448,14 +448,14 @@ func TestHandler_HeartbeatLeaveGroup_EndToEnd(t *testing.T) { |
|
|
|
// Create two handlers connected via pipe to simulate client-server
|
|
|
|
server := NewHandler() |
|
|
|
defer server.Close() |
|
|
|
|
|
|
|
|
|
|
|
client := NewHandler() |
|
|
|
defer client.Close() |
|
|
|
|
|
|
|
|
|
|
|
serverConn, clientConn := net.Pipe() |
|
|
|
defer serverConn.Close() |
|
|
|
defer clientConn.Close() |
|
|
|
|
|
|
|
|
|
|
|
// Setup consumer group on server
|
|
|
|
group := server.groupCoordinator.GetOrCreateGroup("test-group") |
|
|
|
group.Mu.Lock() |
|
|
|
@ -468,18 +468,18 @@ func TestHandler_HeartbeatLeaveGroup_EndToEnd(t *testing.T) { |
|
|
|
LastHeartbeat: time.Now().Add(-10 * time.Second), |
|
|
|
} |
|
|
|
group.Mu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
// Test heartbeat
|
|
|
|
heartbeatRequestBody := createHeartbeatRequestBody("test-group", 1, "member1") |
|
|
|
heartbeatResponse, err := server.handleHeartbeat(456, heartbeatRequestBody) |
|
|
|
if err != nil { |
|
|
|
t.Fatalf("heartbeat failed: %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if len(heartbeatResponse) < 8 { |
|
|
|
t.Fatalf("heartbeat response too short: %d bytes", len(heartbeatResponse)) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Verify heartbeat was processed
|
|
|
|
group.Mu.RLock() |
|
|
|
member := group.Members["member1"] |
|
|
|
@ -487,24 +487,24 @@ func TestHandler_HeartbeatLeaveGroup_EndToEnd(t *testing.T) { |
|
|
|
t.Error("heartbeat timestamp was not updated") |
|
|
|
} |
|
|
|
group.Mu.RUnlock() |
|
|
|
|
|
|
|
|
|
|
|
// Test leave group
|
|
|
|
leaveGroupRequestBody := createLeaveGroupRequestBody("test-group", "member1") |
|
|
|
leaveGroupResponse, err := server.handleLeaveGroup(457, leaveGroupRequestBody) |
|
|
|
if err != nil { |
|
|
|
t.Fatalf("leave group failed: %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if len(leaveGroupResponse) < 8 { |
|
|
|
t.Fatalf("leave group response too short: %d bytes", len(leaveGroupResponse)) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Verify member left and group became empty
|
|
|
|
group.Mu.RLock() |
|
|
|
if len(group.Members) != 0 { |
|
|
|
t.Errorf("expected 0 members after leave, got %d", len(group.Members)) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if group.State != consumer.GroupStateEmpty { |
|
|
|
t.Errorf("expected group state Empty, got %s", group.State) |
|
|
|
} |
|
|
|
@ -515,45 +515,45 @@ func TestHandler_HeartbeatLeaveGroup_EndToEnd(t *testing.T) { |
|
|
|
|
|
|
|
func createHeartbeatRequestBody(groupID string, generationID int32, memberID string) []byte { |
|
|
|
body := make([]byte, 0, 64) |
|
|
|
|
|
|
|
|
|
|
|
// Group ID (string)
|
|
|
|
groupIDBytes := []byte(groupID) |
|
|
|
groupIDLength := make([]byte, 2) |
|
|
|
binary.BigEndian.PutUint16(groupIDLength, uint16(len(groupIDBytes))) |
|
|
|
body = append(body, groupIDLength...) |
|
|
|
body = append(body, groupIDBytes...) |
|
|
|
|
|
|
|
|
|
|
|
// Generation ID (4 bytes)
|
|
|
|
generationIDBytes := make([]byte, 4) |
|
|
|
binary.BigEndian.PutUint32(generationIDBytes, uint32(generationID)) |
|
|
|
body = append(body, generationIDBytes...) |
|
|
|
|
|
|
|
|
|
|
|
// Member ID (string)
|
|
|
|
memberIDBytes := []byte(memberID) |
|
|
|
memberIDLength := make([]byte, 2) |
|
|
|
binary.BigEndian.PutUint16(memberIDLength, uint16(len(memberIDBytes))) |
|
|
|
body = append(body, memberIDLength...) |
|
|
|
body = append(body, memberIDBytes...) |
|
|
|
|
|
|
|
|
|
|
|
return body |
|
|
|
} |
|
|
|
|
|
|
|
func createLeaveGroupRequestBody(groupID string, memberID string) []byte { |
|
|
|
body := make([]byte, 0, 32) |
|
|
|
|
|
|
|
|
|
|
|
// Group ID (string)
|
|
|
|
groupIDBytes := []byte(groupID) |
|
|
|
groupIDLength := make([]byte, 2) |
|
|
|
binary.BigEndian.PutUint16(groupIDLength, uint16(len(groupIDBytes))) |
|
|
|
body = append(body, groupIDLength...) |
|
|
|
body = append(body, groupIDBytes...) |
|
|
|
|
|
|
|
|
|
|
|
// Member ID (string)
|
|
|
|
memberIDBytes := []byte(memberID) |
|
|
|
memberIDLength := make([]byte, 2) |
|
|
|
binary.BigEndian.PutUint16(memberIDLength, uint16(len(memberIDBytes))) |
|
|
|
body = append(body, memberIDLength...) |
|
|
|
body = append(body, memberIDBytes...) |
|
|
|
|
|
|
|
|
|
|
|
return body |
|
|
|
} |