6161import io .grpc .ConnectivityState ;
6262import io .grpc .LoadBalancer ;
6363import io .grpc .LoadBalancer .Helper ;
64+ import io .grpc .LoadBalancer .PickDetailsConsumer ;
6465import io .grpc .LoadBalancer .PickResult ;
6566import io .grpc .LoadBalancer .PickSubchannelArgs ;
6667import io .grpc .LoadBalancer .ResolvedAddresses ;
@@ -296,6 +297,24 @@ public void nonAggregateCluster_resourceUpdate() {
296297 assertThat (childLbConfig .maxConcurrentRequests ).isEqualTo (200L );
297298 }
298299
300+ @ Test
301+ public void nonAggregateCluster_addsBackendServiceAttributeAndPickDetailsLabel () {
302+ controlPlaneService .setXdsConfig (ADS_TYPE_URL_CDS , ImmutableMap .of (CLUSTER , EDS_CLUSTER ));
303+ startXdsDepManager ();
304+
305+ FakeLoadBalancer childBalancer = Iterables .getOnlyElement (childBalancers );
306+ assertThat (childBalancer .attributes .get (NameResolver .ATTR_BACKEND_SERVICE )).isEqualTo (CLUSTER );
307+ childBalancer .deliverSubchannelState (PickResult .withNoResult (), ConnectivityState .READY );
308+
309+ verify (helper ).updateBalancingState (eq (ConnectivityState .READY ), pickerCaptor .capture ());
310+ PickDetailsConsumer detailsConsumer = mock (PickDetailsConsumer .class );
311+ PickResult result =
312+ pickerCaptor .getValue ().pickSubchannel (newPickSubchannelArgs (detailsConsumer ));
313+
314+ assertThat (result .getStatus ().isOk ()).isTrue ();
315+ verify (detailsConsumer ).addOptionalLabel ("grpc.lb.backend_service" , CLUSTER );
316+ }
317+
299318 @ Test
300319 public void nonAggregateCluster_resourceRevoked () {
301320 lbRegistry .register (new PriorityLoadBalancerProvider ());
@@ -429,6 +448,73 @@ public void discoverAggregateCluster_createsPriorityLbPolicy() {
429448 .isEqualTo ("cds_experimental" );
430449 }
431450
451+ @ Test
452+ public void aggregateCluster_doesNotAddBackendServiceAttributeAndPickDetailsLabelFromRoot () {
453+ String cluster1 = "cluster-01.googleapis.com" ;
454+ controlPlaneService .setXdsConfig (ADS_TYPE_URL_CDS , ImmutableMap .of (
455+ // CLUSTER (aggr.) -> [cluster1 (EDS)]
456+ CLUSTER , Cluster .newBuilder ()
457+ .setName (CLUSTER )
458+ .setClusterType (Cluster .CustomClusterType .newBuilder ()
459+ .setName ("envoy.clusters.aggregate" )
460+ .setTypedConfig (Any .pack (ClusterConfig .newBuilder ()
461+ .addClusters (cluster1 )
462+ .build ())))
463+ .build (),
464+ cluster1 , EDS_CLUSTER .toBuilder ().setName (cluster1 ).build ()));
465+ startXdsDepManager ();
466+
467+ FakeLoadBalancer childBalancer = Iterables .getOnlyElement (childBalancers );
468+ assertThat (childBalancer .attributes .get (NameResolver .ATTR_BACKEND_SERVICE )).isNull ();
469+ childBalancer .deliverSubchannelState (PickResult .withNoResult (), ConnectivityState .READY );
470+
471+ verify (helper ).updateBalancingState (eq (ConnectivityState .READY ), pickerCaptor .capture ());
472+ PickDetailsConsumer detailsConsumer = mock (PickDetailsConsumer .class );
473+ PickResult result =
474+ pickerCaptor .getValue ().pickSubchannel (newPickSubchannelArgs (detailsConsumer ));
475+
476+ assertThat (result .getStatus ().isOk ()).isTrue ();
477+ verify (detailsConsumer , never ()).addOptionalLabel (eq ("grpc.lb.backend_service" ), any ());
478+ }
479+
480+ @ Test
481+ public void aggregateCluster_leafAddsBackendServicePickDetailsLabel () {
482+ lbRegistry .register (new PriorityLoadBalancerProvider ());
483+ CdsLoadBalancerProvider cdsLoadBalancerProvider = new CdsLoadBalancerProvider (lbRegistry );
484+ lbRegistry .register (cdsLoadBalancerProvider );
485+ loadBalancer = (CdsLoadBalancer2 ) cdsLoadBalancerProvider .newLoadBalancer (helper );
486+
487+ String cluster1 = "cluster-01.googleapis.com" ;
488+ controlPlaneService .setXdsConfig (ADS_TYPE_URL_CDS , ImmutableMap .of (
489+ // CLUSTER (aggr.) -> [cluster1 (EDS)]
490+ CLUSTER , Cluster .newBuilder ()
491+ .setName (CLUSTER )
492+ .setClusterType (Cluster .CustomClusterType .newBuilder ()
493+ .setName ("envoy.clusters.aggregate" )
494+ .setTypedConfig (Any .pack (ClusterConfig .newBuilder ()
495+ .addClusters (cluster1 )
496+ .build ())))
497+ .build (),
498+ cluster1 , EDS_CLUSTER .toBuilder ().setName (cluster1 ).build ()));
499+ startXdsDepManager ();
500+
501+ FakeLoadBalancer childBalancer = Iterables .getOnlyElement (childBalancers );
502+ ClusterImplConfig clusterImplConfig = (ClusterImplConfig ) childBalancer .config ;
503+ assertThat (clusterImplConfig .cluster ).isEqualTo (cluster1 );
504+ assertThat (childBalancer .attributes .get (NameResolver .ATTR_BACKEND_SERVICE ))
505+ .isEqualTo (cluster1 );
506+ childBalancer .deliverSubchannelState (PickResult .withNoResult (), ConnectivityState .READY );
507+
508+ verify (helper ).updateBalancingState (eq (ConnectivityState .READY ), pickerCaptor .capture ());
509+ PickDetailsConsumer detailsConsumer = mock (PickDetailsConsumer .class );
510+ PickResult result =
511+ pickerCaptor .getValue ().pickSubchannel (newPickSubchannelArgs (detailsConsumer ));
512+
513+ assertThat (result .getStatus ().isOk ()).isTrue ();
514+ verify (detailsConsumer ).addOptionalLabel ("grpc.lb.backend_service" , cluster1 );
515+ verify (detailsConsumer , never ()).addOptionalLabel ("grpc.lb.backend_service" , CLUSTER );
516+ }
517+
432518 @ Test
433519 // Both priorities will get tried using real priority LB policy.
434520 public void discoverAggregateCluster_testChildCdsLbPolicyParsing () {
@@ -462,12 +548,16 @@ public void discoverAggregateCluster_testChildCdsLbPolicyParsing() {
462548 .isEqualTo ("cluster-01.googleapis.com" );
463549 assertThat (cluster1ImplConfig .edsServiceName )
464550 .isEqualTo ("backend-service-1.googleapis.com" );
551+ assertThat (childBalancers .get (0 ).attributes .get (NameResolver .ATTR_BACKEND_SERVICE ))
552+ .isEqualTo (cluster1 );
465553 ClusterImplConfig cluster2ImplConfig =
466554 (ClusterImplConfig ) childBalancers .get (1 ).config ;
467555 assertThat (cluster2ImplConfig .cluster )
468556 .isEqualTo ("cluster-02.googleapis.com" );
469557 assertThat (cluster2ImplConfig .edsServiceName )
470558 .isEqualTo ("backend-service-1.googleapis.com" );
559+ assertThat (childBalancers .get (1 ).attributes .get (NameResolver .ATTR_BACKEND_SERVICE ))
560+ .isEqualTo (cluster2 );
471561 }
472562
473563 @ Test
@@ -577,7 +667,9 @@ public void unknownLbProvider() {
577667 startXdsDepManager ();
578668 verify (helper ).updateBalancingState (
579669 eq (ConnectivityState .TRANSIENT_FAILURE ), pickerCaptor .capture ());
580- PickResult result = pickerCaptor .getValue ().pickSubchannel (mock (PickSubchannelArgs .class ));
670+ PickResult result =
671+ pickerCaptor .getValue ().pickSubchannel (
672+ newPickSubchannelArgs (mock (PickDetailsConsumer .class )));
581673 Status actualStatus = result .getStatus ();
582674 assertThat (actualStatus .getCode ()).isEqualTo (Status .Code .UNAVAILABLE );
583675 assertThat (actualStatus .getDescription ()).contains ("Invalid LoadBalancingPolicy" );
@@ -605,7 +697,9 @@ public void invalidLbConfig() {
605697 startXdsDepManager ();
606698 verify (helper ).updateBalancingState (
607699 eq (ConnectivityState .TRANSIENT_FAILURE ), pickerCaptor .capture ());
608- PickResult result = pickerCaptor .getValue ().pickSubchannel (mock (PickSubchannelArgs .class ));
700+ PickResult result =
701+ pickerCaptor .getValue ().pickSubchannel (
702+ newPickSubchannelArgs (mock (PickDetailsConsumer .class )));
609703 Status actualStatus = result .getStatus ();
610704 assertThat (actualStatus .getCode ()).isEqualTo (Status .Code .UNAVAILABLE );
611705 assertThat (actualStatus .getDescription ()).contains ("Invalid 'minRingSize'" );
@@ -639,12 +733,19 @@ private void startXdsDepManager(final CdsConfig cdsConfig) {
639733 }
640734
641735 private static void assertPickerStatus (SubchannelPicker picker , Status expectedStatus ) {
642- PickResult result = picker .pickSubchannel (mock (PickSubchannelArgs .class ));
736+ PickResult result = picker .pickSubchannel (
737+ newPickSubchannelArgs (mock (PickDetailsConsumer .class )));
643738 Status actualStatus = result .getStatus ();
644739 assertThat (actualStatus .getCode ()).isEqualTo (expectedStatus .getCode ());
645740 assertThat (actualStatus .getDescription ()).isEqualTo (expectedStatus .getDescription ());
646741 }
647742
743+ private static PickSubchannelArgs newPickSubchannelArgs (PickDetailsConsumer pickDetailsConsumer ) {
744+ PickSubchannelArgs args = mock (PickSubchannelArgs .class );
745+ when (args .getPickDetailsConsumer ()).thenReturn (pickDetailsConsumer );
746+ return args ;
747+ }
748+
648749 private final class FakeLoadBalancerProvider extends LoadBalancerProvider {
649750 private final String policyName ;
650751 private final LoadBalancerProvider configParsingDelegate ;
@@ -660,7 +761,7 @@ private final class FakeLoadBalancerProvider extends LoadBalancerProvider {
660761
661762 @ Override
662763 public LoadBalancer newLoadBalancer (Helper helper ) {
663- FakeLoadBalancer balancer = new FakeLoadBalancer (policyName );
764+ FakeLoadBalancer balancer = new FakeLoadBalancer (policyName , helper );
664765 childBalancers .add (balancer );
665766 return balancer ;
666767 }
@@ -692,17 +793,21 @@ public NameResolver.ConfigOrError parseLoadBalancingPolicyConfig(
692793
693794 private final class FakeLoadBalancer extends LoadBalancer {
694795 private final String name ;
796+ private final Helper helper ;
695797 private Object config ;
798+ private Attributes attributes ;
696799 private Status upstreamError ;
697800 private boolean shutdown ;
698801
699- FakeLoadBalancer (String name ) {
802+ FakeLoadBalancer (String name , Helper helper ) {
700803 this .name = name ;
804+ this .helper = helper ;
701805 }
702806
703807 @ Override
704808 public Status acceptResolvedAddresses (ResolvedAddresses resolvedAddresses ) {
705809 config = resolvedAddresses .getLoadBalancingPolicyConfig ();
810+ attributes = resolvedAddresses .getAttributes ();
706811 return Status .OK ;
707812 }
708813
@@ -716,5 +821,15 @@ public void shutdown() {
716821 shutdown = true ;
717822 childBalancers .remove (this );
718823 }
824+
825+ void deliverSubchannelState (final PickResult result , ConnectivityState state ) {
826+ SubchannelPicker picker = new SubchannelPicker () {
827+ @ Override
828+ public PickResult pickSubchannel (PickSubchannelArgs args ) {
829+ return result ;
830+ }
831+ };
832+ helper .updateBalancingState (state , picker );
833+ }
719834 }
720835}
0 commit comments