@@ -32,6 +32,7 @@ import (
3232 "google.golang.org/grpc/internal/grpctest"
3333 "google.golang.org/grpc/internal/stubserver"
3434 "google.golang.org/grpc/internal/testutils/roundrobin"
35+ "google.golang.org/grpc/internal/testutils/stats"
3536 "google.golang.org/grpc/orca"
3637 "google.golang.org/grpc/peer"
3738 "google.golang.org/grpc/resolver"
8182 WeightUpdatePeriod : stringp (".050s" ),
8283 ErrorUtilizationPenalty : float64p (0 ),
8384 }
85+ testMetricsConfig = iwrr.LBConfig {
86+ EnableOOBLoadReport : boolp (false ),
87+ OOBReportingPeriod : stringp ("0.005s" ),
88+ BlackoutPeriod : stringp ("0s" ),
89+ WeightExpirationPeriod : stringp ("60s" ),
90+ WeightUpdatePeriod : stringp (".050s" ),
91+ ErrorUtilizationPenalty : float64p (0 ),
92+ }
8493)
8594
8695type testServer struct {
@@ -196,6 +205,43 @@ func (s) TestBalancer_OneAddress(t *testing.T) {
196205 }
197206}
198207
208+ // TestWRRMetricsBasic tests metrics emitted from the WRR balancer. It
209+ // configures a weighted round robin balancer as the top level balancer of a
210+ // ClientConn, and configures a fake stats handler on the ClientConn to receive
211+ // metrics. It verifies stats emitted from the Weighted Round Robin Balancer on
212+ // balancer startup case which triggers the first picker and scheduler update
213+ // before any load reports are received.
214+ //
215+ // Note that this test and others, metrics emission asssertions are a snapshot
216+ // of the most recently emitted metrics. This is due to the nondeterminism of
217+ // scheduler updates with respect to test bodies, so the assertions made are
218+ // from the most recently synced state of the system (picker/scheduler) from the
219+ // test body.
220+ func (s ) TestWRRMetricsBasic (t * testing.T ) {
221+ ctx , cancel := context .WithTimeout (context .Background (), defaultTestTimeout )
222+ defer cancel ()
223+
224+ srv := startServer (t , reportCall )
225+ sc := svcConfig (t , testMetricsConfig )
226+
227+ mr := stats .NewTestMetricsRecorder (t , []string {"grpc.lb.wrr.rr_fallback" , "grpc.lb.wrr.endpoint_weight_not_yet_usable" , "grpc.lb.wrr.endpoint_weight_stale" , "grpc.lb.wrr.endpoint_weights" })
228+ if err := srv .StartClient (grpc .WithDefaultServiceConfig (sc ), grpc .WithStatsHandler (mr )); err != nil {
229+ t .Fatalf ("Error starting client: %v" , err )
230+ }
231+ srv .callMetrics .SetQPS (float64 (1 ))
232+
233+ if _ , err := srv .Client .EmptyCall (ctx , & testpb.Empty {}); err != nil {
234+ t .Fatalf ("Error from EmptyCall: %v" , err )
235+ }
236+
237+ mr .AssertDataForMetric ("grpc.lb.wrr.rr_fallback" , 1 ) // Falls back because only one SubConn.
238+ mr .AssertDataForMetric ("grpc.lb.wrr.endpoint_weight_stale" , 0 ) // The endpoint weight has not expired so this is 0 (never emitted).
239+ mr .AssertDataForMetric ("grpc.lb.wrr.endpoint_weight_not_yet_usable" , 1 )
240+ // Unusable, so no endpoint weight. Due to only one SubConn, this will never
241+ // update the weight. Thus, this will stay 0.
242+ mr .AssertDataForMetric ("grpc.lb.wrr.endpoint_weights" , 0 )
243+ }
244+
199245// Tests two addresses with ORCA reporting disabled (should fall back to pure
200246// RR).
201247func (s ) TestBalancer_TwoAddresses_ReportingDisabled (t * testing.T ) {
@@ -509,7 +555,8 @@ func (s) TestBalancer_TwoAddresses_BlackoutPeriod(t *testing.T) {
509555 cfg := oobConfig
510556 cfg .BlackoutPeriod = tc .blackoutPeriodCfg
511557 sc := svcConfig (t , cfg )
512- if err := srv1 .StartClient (grpc .WithDefaultServiceConfig (sc )); err != nil {
558+ mr := stats .NewTestMetricsRecorder (t , []string {"grpc.lb.wrr.rr_fallback" , "grpc.lb.wrr.endpoint_weight_not_yet_usable" , "grpc.lb.wrr.endpoint_weight_stale" , "grpc.lb.wrr.endpoint_weights" })
559+ if err := srv1 .StartClient (grpc .WithDefaultServiceConfig (sc ), grpc .WithStatsHandler (mr )); err != nil {
513560 t .Fatalf ("Error starting client: %v" , err )
514561 }
515562 addrs := []resolver.Address {{Addr : srv1 .Address }, {Addr : srv2 .Address }}
@@ -536,12 +583,20 @@ func (s) TestBalancer_TwoAddresses_BlackoutPeriod(t *testing.T) {
536583 // Wait for the weight update period to allow the new weights to be processed.
537584 time .Sleep (weightUpdatePeriod )
538585 checkWeights (ctx , t , srvWeight {srv1 , 1 }, srvWeight {srv2 , 10 })
586+
587+ mr .AssertDataForMetric ("grpc.lb.wrr.rr_fallback" , 1 )
588+ mr .AssertDataForMetric ("grpc.lb.wrr.endpoint_weight_stale" , 0 )
589+ mr .AssertDataForMetric ("grpc.lb.wrr.endpoint_weight_not_yet_usable" , 1 )
590+ // Either 10 or 100, dependent on whatever ordering SubConns are
591+ // processed, which is nondeterministic.
592+ mr .AssertEitherDataForMetric ("grpc.lb.wrr.endpoint_weights" , 10 , 100 )
539593 }
540594}
541595
542596// Tests that the weight expiration period causes backends to use 0 as their
543597// weight (meaning to use the average weight) once the expiration period
544- // elapses.
598+ // elapses. After the weight expires, the expected metrics to be emitted from
599+ // WRR are also configured.
545600func (s ) TestBalancer_TwoAddresses_WeightExpiration (t * testing.T ) {
546601 ctx , cancel := context .WithTimeout (context .Background (), defaultTestTimeout )
547602 defer cancel ()
@@ -577,7 +632,8 @@ func (s) TestBalancer_TwoAddresses_WeightExpiration(t *testing.T) {
577632 cfg := oobConfig
578633 cfg .OOBReportingPeriod = stringp ("60s" )
579634 sc := svcConfig (t , cfg )
580- if err := srv1 .StartClient (grpc .WithDefaultServiceConfig (sc )); err != nil {
635+ mr := stats .NewTestMetricsRecorder (t , []string {"grpc.lb.wrr.rr_fallback" , "grpc.lb.wrr.endpoint_weight_not_yet_usable" , "grpc.lb.wrr.endpoint_weight_stale" , "grpc.lb.wrr.endpoint_weights" })
636+ if err := srv1 .StartClient (grpc .WithDefaultServiceConfig (sc ), grpc .WithStatsHandler (mr )); err != nil {
581637 t .Fatalf ("Error starting client: %v" , err )
582638 }
583639 addrs := []resolver.Address {{Addr : srv1 .Address }, {Addr : srv2 .Address }}
@@ -605,6 +661,11 @@ func (s) TestBalancer_TwoAddresses_WeightExpiration(t *testing.T) {
605661 // Wait for the weight expiration period so the weights have expired.
606662 time .Sleep (weightUpdatePeriod )
607663 checkWeights (ctx , t , srvWeight {srv1 , 1 }, srvWeight {srv2 , 1 })
664+
665+ mr .AssertDataForMetric ("grpc.lb.wrr.rr_fallback" , 1 )
666+ mr .AssertDataForMetric ("grpc.lb.wrr.endpoint_weight_stale" , 1 )
667+ mr .AssertDataForMetric ("grpc.lb.wrr.endpoint_weight_not_yet_usable" , 1 )
668+ mr .AssertDataForMetric ("grpc.lb.wrr.endpoint_weights" , 0 )
608669}
609670
610671// Tests logic surrounding subchannel management.
0 commit comments