@@ -64,6 +64,43 @@ func TestNewBatchClient(t *testing.T) {
6464 assert .Equal (t , 1000 , cap (client .messageBuffer ))
6565 })
6666
67+ t .Run ("WithMaxGRPCRequestSize" , func (t * testing.T ) {
68+ t .Run ("applies value at or above minimum" , func (t * testing.T ) {
69+ client , err := NewBatchClient (mocks .NewClient (t ), WithMaxGRPCRequestSize (4 * 1024 * 1024 ))
70+ require .NoError (t , err )
71+ assert .Equal (t , 4 * 1024 * 1024 , client .maxGRPCRequestSize )
72+ assert .Equal (t , 4 * 1024 * 1024 - grpcFramingOverhead , client .effectiveMaxRequestSize )
73+ })
74+
75+ t .Run ("clamps value below minimum to minMaxGRPCRequestSize" , func (t * testing.T ) {
76+ client , err := NewBatchClient (mocks .NewClient (t ), WithMaxGRPCRequestSize (512 ))
77+ require .NoError (t , err )
78+ assert .Equal (t , minMaxGRPCRequestSize , client .maxGRPCRequestSize )
79+ assert .Equal (t , minMaxGRPCRequestSize - grpcFramingOverhead , client .effectiveMaxRequestSize )
80+ })
81+
82+ t .Run ("clamps zero to minMaxGRPCRequestSize" , func (t * testing.T ) {
83+ client , err := NewBatchClient (mocks .NewClient (t ), WithMaxGRPCRequestSize (0 ))
84+ require .NoError (t , err )
85+ assert .Equal (t , minMaxGRPCRequestSize , client .maxGRPCRequestSize )
86+ assert .Equal (t , minMaxGRPCRequestSize - grpcFramingOverhead , client .effectiveMaxRequestSize )
87+ })
88+
89+ t .Run ("clamps negative to minMaxGRPCRequestSize" , func (t * testing.T ) {
90+ client , err := NewBatchClient (mocks .NewClient (t ), WithMaxGRPCRequestSize (- 1 ))
91+ require .NoError (t , err )
92+ assert .Equal (t , minMaxGRPCRequestSize , client .maxGRPCRequestSize )
93+ assert .Equal (t , minMaxGRPCRequestSize - grpcFramingOverhead , client .effectiveMaxRequestSize )
94+ })
95+
96+ t .Run ("exact minimum is accepted as-is" , func (t * testing.T ) {
97+ client , err := NewBatchClient (mocks .NewClient (t ), WithMaxGRPCRequestSize (minMaxGRPCRequestSize ))
98+ require .NoError (t , err )
99+ assert .Equal (t , minMaxGRPCRequestSize , client .maxGRPCRequestSize )
100+ assert .Equal (t , minMaxGRPCRequestSize - grpcFramingOverhead , client .effectiveMaxRequestSize )
101+ })
102+ })
103+
67104 t .Run ("records failure metrics when request exceeds configured max grpc size" , func (t * testing.T ) {
68105 reader , restore := useTestMeterProvider (t )
69106 defer restore ()
@@ -79,9 +116,11 @@ func TestNewBatchClient(t *testing.T) {
79116 WithBatchSize (1 ),
80117 WithBatchInterval (time .Second ),
81118 WithMessageBuffer (10 ),
82- WithMaxGRPCRequestSize (maxGRPCSize ),
83119 )
84120 require .NoError (t , err )
121+ client .maxGRPCRequestSize = maxGRPCSize
122+ client .effectiveMaxRequestSize = maxGRPCSize
123+ require .NoError (t , err )
85124 client .Start (t .Context ())
86125
87126 err = client .QueueMessage (& chipingress.CloudEventPb {
@@ -303,8 +342,10 @@ func TestSendBatch(t *testing.T) {
303342 }).
304343 Times (3 )
305344
306- client , err := NewBatchClient (mockClient , WithMaxGRPCRequestSize ( maxRequestSize ) )
345+ client , err := NewBatchClient (mockClient )
307346 require .NoError (t , err )
347+ client .maxGRPCRequestSize = maxRequestSize
348+ client .effectiveMaxRequestSize = maxRequestSize
308349
309350 messages := make ([]* messageWithCallback , 0 , len (events ))
310351 for _ , event := range events {
@@ -339,14 +380,71 @@ func TestSendBatch(t *testing.T) {
339380 mockClient .AssertExpectations (t )
340381 })
341382
383+ t .Run ("records batch_splits_total metric when batch is split" , func (t * testing.T ) {
384+ reader , restore := useTestMeterProvider (t )
385+ defer restore ()
386+
387+ events := []* chipingress.CloudEventPb {
388+ largeTestEvent ("split-metric-1" ),
389+ largeTestEvent ("split-metric-2" ),
390+ largeTestEvent ("split-metric-3" ),
391+ }
392+ // Set maxRequestSize so that 2 events fit but 3 do not, forcing a split.
393+ maxRequestSize := proto .Size (& chipingress.CloudEventBatch {Events : events [:2 ]})
394+
395+ mockClient := mocks .NewClient (t )
396+ done := make (chan struct {})
397+ var mu sync.Mutex
398+ var publishCount int
399+
400+ mockClient .
401+ On ("PublishBatch" , mock .Anything , mock .Anything ).
402+ Return (& chipingress.PublishResponse {}, nil ).
403+ Run (func (args mock.Arguments ) {
404+ mu .Lock ()
405+ publishCount ++
406+ if publishCount == 2 {
407+ close (done )
408+ }
409+ mu .Unlock ()
410+ })
411+
412+ client , err := NewBatchClient (mockClient )
413+ require .NoError (t , err )
414+ client .maxGRPCRequestSize = maxRequestSize
415+ client .effectiveMaxRequestSize = maxRequestSize
416+
417+ messages := make ([]* messageWithCallback , 0 , len (events ))
418+ for _ , event := range events {
419+ messages = append (messages , & messageWithCallback {event : event })
420+ }
421+
422+ client .sendBatch (t .Context (), messages )
423+
424+ select {
425+ case <- done :
426+ case <- time .After (time .Second ):
427+ t .Fatal ("timeout waiting for split batches to be sent" )
428+ }
429+
430+ rm := collectResourceMetrics (t , reader )
431+ splitsMetric := mustMetric (t , rm , "chip_ingress.batch.batch_splits_total" )
432+ splitsSum , ok := splitsMetric .Data .(metricdata.Sum [int64 ])
433+ require .True (t , ok )
434+ require .Len (t , splitsSum .DataPoints , 1 )
435+ assert .Equal (t , int64 (1 ), splitsSum .DataPoints [0 ].Value )
436+ })
437+
342438 t .Run ("doesn't publish a single event over max gRPC request size" , func (t * testing.T ) {
343439 mockClient := mocks .NewClient (t )
344440 callbackDone := make (chan error , 1 )
345441 event := largeTestEvent ("oversized-id" )
346442 maxRequestSize := proto .Size (& chipingress.CloudEventBatch {Events : []* chipingress.CloudEventPb {event }}) - 1
347443
348- client , err := NewBatchClient (mockClient , WithMaxGRPCRequestSize ( maxRequestSize ) )
444+ client , err := NewBatchClient (mockClient )
349445 require .NoError (t , err )
446+ client .maxGRPCRequestSize = maxRequestSize
447+ client .effectiveMaxRequestSize = maxRequestSize
350448
351449 client .sendBatch (t .Context (), []* messageWithCallback {
352450 {
@@ -1350,7 +1448,7 @@ func TestBatchClient_Metrics(t *testing.T) {
13501448 WithBatchSize (1 ),
13511449 WithBatchInterval (time .Second ),
13521450 WithMessageBuffer (10 ),
1353- WithMaxGRPCRequestSize (2048 ),
1451+ WithMaxGRPCRequestSize (minMaxGRPCRequestSize ),
13541452 )
13551453 require .NoError (t , err )
13561454 client .Start (t .Context ())
@@ -1386,7 +1484,7 @@ func TestBatchClient_Metrics(t *testing.T) {
13861484 reqSize := mustMetric (t , rm , "chip_ingress.batch.request_size_bytes" )
13871485 reqSizeHist , ok := reqSize .Data .(metricdata.Histogram [int64 ])
13881486 require .True (t , ok )
1389- reqSizePoint := mustInt64HistogramPointWithIntAttr (t , reqSizeHist , "max_grpc_request_size_bytes" , 2048 )
1487+ reqSizePoint := mustInt64HistogramPointWithIntAttr (t , reqSizeHist , "max_grpc_request_size_bytes" , minMaxGRPCRequestSize )
13901488 assert .GreaterOrEqual (t , reqSizePoint .Count , uint64 (1 ))
13911489
13921490 latency := mustMetric (t , rm , "chip_ingress.batch.request_latency_ms" )
@@ -1401,7 +1499,7 @@ func TestBatchClient_Metrics(t *testing.T) {
14011499 require .NotEmpty (t , configGauge .DataPoints )
14021500 assert .Equal (t , int64 (1 ), configGauge .DataPoints [0 ].Value )
14031501 assert .True (t , hasIntAttr (configGauge .DataPoints [0 ].Attributes , "max_batch_size" , 1 ))
1404- assert .True (t , hasIntAttr (configGauge .DataPoints [0 ].Attributes , "max_grpc_request_size_bytes" , 2048 ))
1502+ assert .True (t , hasIntAttr (configGauge .DataPoints [0 ].Attributes , "max_grpc_request_size_bytes" , minMaxGRPCRequestSize ))
14051503 })
14061504
14071505 t .Run ("records failure counters and latency" , func (t * testing.T ) {
@@ -1540,11 +1638,12 @@ func BenchmarkSendBatch(b *testing.B) {
15401638 WithBatchSize (100 ),
15411639 WithMessageBuffer (b .N * 100 + 10 ),
15421640 WithBatchInterval (time .Hour ),
1543- WithMaxGRPCRequestSize (512 ),
15441641 )
15451642 if err != nil {
15461643 b .Fatal (err )
15471644 }
1645+ client .maxGRPCRequestSize = 512
1646+ client .effectiveMaxRequestSize = 512
15481647 client .Start (b .Context ())
15491648 defer client .Stop ()
15501649
0 commit comments