|
|
@@ -3,6 +3,9 @@ package sarama
|
|
|
import (
|
|
|
"fmt"
|
|
|
"testing"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "github.com/rcrowley/go-metrics"
|
|
|
)
|
|
|
|
|
|
func ExampleBroker() {
|
|
|
@@ -34,6 +37,11 @@ func (m mockEncoder) encode(pe packetEncoder) error {
|
|
|
return pe.putRawBytes(m.bytes)
|
|
|
}
|
|
|
|
|
|
+type brokerMetrics struct {
|
|
|
+ bytesRead int
|
|
|
+ bytesWritten int
|
|
|
+}
|
|
|
+
|
|
|
func TestBrokerAccessors(t *testing.T) {
|
|
|
broker := NewBroker("abc:123")
|
|
|
|
|
|
@@ -52,36 +60,53 @@ func TestBrokerAccessors(t *testing.T) {
|
|
|
}
|
|
|
|
|
|
func TestSimpleBrokerCommunication(t *testing.T) {
|
|
|
- mb := NewMockBroker(t, 0)
|
|
|
- defer mb.Close()
|
|
|
-
|
|
|
- broker := NewBroker(mb.Addr())
|
|
|
- conf := NewConfig()
|
|
|
- conf.Version = V0_10_0_0
|
|
|
- err := broker.Open(conf)
|
|
|
- if err != nil {
|
|
|
- t.Fatal(err)
|
|
|
- }
|
|
|
-
|
|
|
for _, tt := range brokerTestTable {
|
|
|
+ Logger.Printf("Testing broker communication for %s", tt.name)
|
|
|
+ mb := NewMockBroker(t, 0)
|
|
|
mb.Returns(&mockEncoder{tt.response})
|
|
|
- }
|
|
|
- for _, tt := range brokerTestTable {
|
|
|
+ pendingNotify := make(chan brokerMetrics)
|
|
|
+ // Register a callback to be notified about successful requests
|
|
|
+ mb.SetNotifier(func(bytesRead, bytesWritten int) {
|
|
|
+ pendingNotify <- brokerMetrics{bytesRead, bytesWritten}
|
|
|
+ })
|
|
|
+ broker := NewBroker(mb.Addr())
|
|
|
+ // Set the broker id in order to validate local broker metrics
|
|
|
+ broker.id = 0
|
|
|
+ conf := NewConfig()
|
|
|
+ conf.Version = V0_10_0_0
|
|
|
+ // Use a new registry every time to prevent side effect caused by the global one
|
|
|
+ conf.MetricRegistry = metrics.NewRegistry()
|
|
|
+ err := broker.Open(conf)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
tt.runner(t, broker)
|
|
|
+ err = broker.Close()
|
|
|
+ if err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ // Wait up to 500 ms for the remote broker to process the request and
|
|
|
+ // notify us about the metrics
|
|
|
+ timeout := 500 * time.Millisecond
|
|
|
+ select {
|
|
|
+ case mockBrokerMetrics := <-pendingNotify:
|
|
|
+ validateBrokerMetrics(t, broker, mockBrokerMetrics)
|
|
|
+ case <-time.After(timeout):
|
|
|
+ t.Errorf("No request received for: %s after waiting for %v", tt.name, timeout)
|
|
|
+ }
|
|
|
+ mb.Close()
|
|
|
}
|
|
|
|
|
|
- err = broker.Close()
|
|
|
- if err != nil {
|
|
|
- t.Error(err)
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
// We're not testing encoding/decoding here, so most of the requests/responses will be empty for simplicity's sake
|
|
|
var brokerTestTable = []struct {
|
|
|
+ name string
|
|
|
response []byte
|
|
|
runner func(*testing.T, *Broker)
|
|
|
}{
|
|
|
- {[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
|
+ {"MetadataRequest",
|
|
|
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
|
func(t *testing.T, broker *Broker) {
|
|
|
request := MetadataRequest{}
|
|
|
response, err := broker.GetMetadata(&request)
|
|
|
@@ -93,7 +118,8 @@ var brokerTestTable = []struct {
|
|
|
}
|
|
|
}},
|
|
|
|
|
|
- {[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 't', 0x00, 0x00, 0x00, 0x00},
|
|
|
+ {"ConsumerMetadataRequest",
|
|
|
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 't', 0x00, 0x00, 0x00, 0x00},
|
|
|
func(t *testing.T, broker *Broker) {
|
|
|
request := ConsumerMetadataRequest{}
|
|
|
response, err := broker.GetConsumerMetadata(&request)
|
|
|
@@ -105,7 +131,8 @@ var brokerTestTable = []struct {
|
|
|
}
|
|
|
}},
|
|
|
|
|
|
- {[]byte{},
|
|
|
+ {"ProduceRequest (NoResponse)",
|
|
|
+ []byte{},
|
|
|
func(t *testing.T, broker *Broker) {
|
|
|
request := ProduceRequest{}
|
|
|
request.RequiredAcks = NoResponse
|
|
|
@@ -118,7 +145,8 @@ var brokerTestTable = []struct {
|
|
|
}
|
|
|
}},
|
|
|
|
|
|
- {[]byte{0x00, 0x00, 0x00, 0x00},
|
|
|
+ {"ProduceRequest (WaitForLocal)",
|
|
|
+ []byte{0x00, 0x00, 0x00, 0x00},
|
|
|
func(t *testing.T, broker *Broker) {
|
|
|
request := ProduceRequest{}
|
|
|
request.RequiredAcks = WaitForLocal
|
|
|
@@ -131,7 +159,8 @@ var brokerTestTable = []struct {
|
|
|
}
|
|
|
}},
|
|
|
|
|
|
- {[]byte{0x00, 0x00, 0x00, 0x00},
|
|
|
+ {"FetchRequest",
|
|
|
+ []byte{0x00, 0x00, 0x00, 0x00},
|
|
|
func(t *testing.T, broker *Broker) {
|
|
|
request := FetchRequest{}
|
|
|
response, err := broker.Fetch(&request)
|
|
|
@@ -143,7 +172,8 @@ var brokerTestTable = []struct {
|
|
|
}
|
|
|
}},
|
|
|
|
|
|
- {[]byte{0x00, 0x00, 0x00, 0x00},
|
|
|
+ {"OffsetFetchRequest",
|
|
|
+ []byte{0x00, 0x00, 0x00, 0x00},
|
|
|
func(t *testing.T, broker *Broker) {
|
|
|
request := OffsetFetchRequest{}
|
|
|
response, err := broker.FetchOffset(&request)
|
|
|
@@ -155,7 +185,8 @@ var brokerTestTable = []struct {
|
|
|
}
|
|
|
}},
|
|
|
|
|
|
- {[]byte{0x00, 0x00, 0x00, 0x00},
|
|
|
+ {"OffsetCommitRequest",
|
|
|
+ []byte{0x00, 0x00, 0x00, 0x00},
|
|
|
func(t *testing.T, broker *Broker) {
|
|
|
request := OffsetCommitRequest{}
|
|
|
response, err := broker.CommitOffset(&request)
|
|
|
@@ -167,7 +198,8 @@ var brokerTestTable = []struct {
|
|
|
}
|
|
|
}},
|
|
|
|
|
|
- {[]byte{0x00, 0x00, 0x00, 0x00},
|
|
|
+ {"OffsetRequest",
|
|
|
+ []byte{0x00, 0x00, 0x00, 0x00},
|
|
|
func(t *testing.T, broker *Broker) {
|
|
|
request := OffsetRequest{}
|
|
|
response, err := broker.GetAvailableOffsets(&request)
|
|
|
@@ -179,7 +211,8 @@ var brokerTestTable = []struct {
|
|
|
}
|
|
|
}},
|
|
|
|
|
|
- {[]byte{0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
|
+ {"JoinGroupRequest",
|
|
|
+ []byte{0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
|
func(t *testing.T, broker *Broker) {
|
|
|
request := JoinGroupRequest{}
|
|
|
response, err := broker.JoinGroup(&request)
|
|
|
@@ -191,7 +224,8 @@ var brokerTestTable = []struct {
|
|
|
}
|
|
|
}},
|
|
|
|
|
|
- {[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
|
+ {"SyncGroupRequest",
|
|
|
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
|
func(t *testing.T, broker *Broker) {
|
|
|
request := SyncGroupRequest{}
|
|
|
response, err := broker.SyncGroup(&request)
|
|
|
@@ -203,7 +237,8 @@ var brokerTestTable = []struct {
|
|
|
}
|
|
|
}},
|
|
|
|
|
|
- {[]byte{0x00, 0x00},
|
|
|
+ {"LeaveGroupRequest",
|
|
|
+ []byte{0x00, 0x00},
|
|
|
func(t *testing.T, broker *Broker) {
|
|
|
request := LeaveGroupRequest{}
|
|
|
response, err := broker.LeaveGroup(&request)
|
|
|
@@ -215,7 +250,8 @@ var brokerTestTable = []struct {
|
|
|
}
|
|
|
}},
|
|
|
|
|
|
- {[]byte{0x00, 0x00},
|
|
|
+ {"HeartbeatRequest",
|
|
|
+ []byte{0x00, 0x00},
|
|
|
func(t *testing.T, broker *Broker) {
|
|
|
request := HeartbeatRequest{}
|
|
|
response, err := broker.Heartbeat(&request)
|
|
|
@@ -227,7 +263,8 @@ var brokerTestTable = []struct {
|
|
|
}
|
|
|
}},
|
|
|
|
|
|
- {[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
|
+ {"ListGroupsRequest",
|
|
|
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
|
func(t *testing.T, broker *Broker) {
|
|
|
request := ListGroupsRequest{}
|
|
|
response, err := broker.ListGroups(&request)
|
|
|
@@ -239,7 +276,8 @@ var brokerTestTable = []struct {
|
|
|
}
|
|
|
}},
|
|
|
|
|
|
- {[]byte{0x00, 0x00, 0x00, 0x00},
|
|
|
+ {"DescribeGroupsRequest",
|
|
|
+ []byte{0x00, 0x00, 0x00, 0x00},
|
|
|
func(t *testing.T, broker *Broker) {
|
|
|
request := DescribeGroupsRequest{}
|
|
|
response, err := broker.DescribeGroups(&request)
|
|
|
@@ -251,3 +289,31 @@ var brokerTestTable = []struct {
|
|
|
}
|
|
|
}},
|
|
|
}
|
|
|
+
|
|
|
+func validateBrokerMetrics(t *testing.T, broker *Broker, mockBrokerMetrics brokerMetrics) {
|
|
|
+ metricValidators := newMetricValidators()
|
|
|
+ mockBrokerBytesRead := mockBrokerMetrics.bytesRead
|
|
|
+ mockBrokerBytesWritten := mockBrokerMetrics.bytesWritten
|
|
|
+
|
|
|
+ // Check that the number of bytes sent corresponds to what the mock broker received
|
|
|
+ metricValidators.registerForAllBrokers(broker, countMeterValidator("incoming-byte-rate", mockBrokerBytesWritten))
|
|
|
+ if mockBrokerBytesWritten == 0 {
|
|
|
+ // This a ProduceRequest with NoResponse
|
|
|
+ metricValidators.registerForAllBrokers(broker, countMeterValidator("response-rate", 0))
|
|
|
+ metricValidators.registerForAllBrokers(broker, countHistogramValidator("response-size", 0))
|
|
|
+ metricValidators.registerForAllBrokers(broker, minMaxHistogramValidator("response-size", 0, 0))
|
|
|
+ } else {
|
|
|
+ metricValidators.registerForAllBrokers(broker, countMeterValidator("response-rate", 1))
|
|
|
+ metricValidators.registerForAllBrokers(broker, countHistogramValidator("response-size", 1))
|
|
|
+ metricValidators.registerForAllBrokers(broker, minMaxHistogramValidator("response-size", mockBrokerBytesWritten, mockBrokerBytesWritten))
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check that the number of bytes received corresponds to what the mock broker sent
|
|
|
+ metricValidators.registerForAllBrokers(broker, countMeterValidator("outgoing-byte-rate", mockBrokerBytesRead))
|
|
|
+ metricValidators.registerForAllBrokers(broker, countMeterValidator("request-rate", 1))
|
|
|
+ metricValidators.registerForAllBrokers(broker, countHistogramValidator("request-size", 1))
|
|
|
+ metricValidators.registerForAllBrokers(broker, minMaxHistogramValidator("request-size", mockBrokerBytesRead, mockBrokerBytesRead))
|
|
|
+
|
|
|
+ // Run the validators
|
|
|
+ metricValidators.run(t, broker.conf.MetricRegistry)
|
|
|
+}
|