@@ -41,6 +41,7 @@ import (
4141"google.golang.org/grpc/internal/testutils"
4242"google.golang.org/grpc/internal/testutils/pickfirst"
4343"google.golang.org/grpc/internal/testutils/stats"
44+ "google.golang.org/grpc/metadata"
4445"google.golang.org/grpc/resolver"
4546"google.golang.org/grpc/resolver/manual"
4647"google.golang.org/grpc/status"
@@ -1424,6 +1425,85 @@ func (s) TestPickFirstLeaf_HealthUpdates(t *testing.T) {
14241425testutils .AwaitState (ctx ,t ,cc ,connectivity .TransientFailure )
14251426}
14261427
1428+ // Tests the case where an address update received by the pick_first LB policy
1429+ // differs in metadata which should be ignored by the LB policy. In this case,
1430+ // the test verifies that new connections are not created when the address
1431+ // update only changes the metadata.
1432+ func (s )TestPickFirstLeaf_AddressUpdateWithMetadata (t * testing.T ) {
1433+ dialer := testutils .NewBlockingDialer ()
1434+ dopts := []grpc.DialOption {
1435+ grpc .WithDefaultServiceConfig (fmt .Sprintf (`{"loadBalancingConfig": [{"%s":{}}]}` ,pickfirstleaf .Name )),
1436+ grpc .WithContextDialer (dialer .DialContext ),
1437+ }
1438+ cc ,r ,backends := setupPickFirstLeaf (t ,2 ,dopts ... )
1439+
1440+ // Add a metadata to the addresses before pushing them to the pick_first LB
1441+ // policy through the manual resolver.
1442+ addrs := backends .resolverAddrs ()
1443+ for i := range addrs {
1444+ addrs [i ].Metadata = & metadata.MD {
1445+ "test-metadata-1" : []string {fmt .Sprintf ("%d" ,i )},
1446+ }
1447+ }
1448+ r .UpdateState (resolver.State {Addresses :addrs })
1449+
1450+ // Ensure that RPCs succeed to the expected backend.
1451+ ctx ,cancel := context .WithTimeout (context .Background (),defaultTestTimeout )
1452+ defer cancel ()
1453+ if err := pickfirst .CheckRPCsToBackend (ctx ,cc ,addrs [0 ]);err != nil {
1454+ t .Fatal (err )
1455+ }
1456+
1457+ // Create holds for each backend. This will be used to verify the connection
1458+ // is not re-established.
1459+ holds := backends .holds (dialer )
1460+
1461+ // Add metadata to the addresses before pushing them to the pick_first LB
1462+ // policy through the manual resolver. Leave the order of the addresses
1463+ // unchanged.
1464+ for i := range addrs {
1465+ addrs [i ].Metadata = & metadata.MD {
1466+ "test-metadata-2" : []string {fmt .Sprintf ("%d" ,i )},
1467+ }
1468+ }
1469+ r .UpdateState (resolver.State {Addresses :addrs })
1470+
1471+ // Ensure that no new connection is established.
1472+ for i := range holds {
1473+ sCtx ,sCancel := context .WithTimeout (ctx ,defaultTestShortTimeout )
1474+ defer sCancel ()
1475+ if holds [i ].Wait (sCtx ) {
1476+ t .Fatalf ("Unexpected connection attempt to backend: %s" ,addrs [i ])
1477+ }
1478+ }
1479+
1480+ if err := pickfirst .CheckRPCsToBackend (ctx ,cc ,addrs [0 ]);err != nil {
1481+ t .Fatal (err )
1482+ }
1483+
1484+ // Add metadata to the addresses before pushing them to the pick_first LB
1485+ // policy through the manual resolver. Reverse of the order of addresses.
1486+ for i := range addrs {
1487+ addrs [i ].Metadata = & metadata.MD {
1488+ "test-metadata-3" : []string {fmt .Sprintf ("%d" ,i )},
1489+ }
1490+ }
1491+ addrs [0 ],addrs [1 ]= addrs [1 ],addrs [0 ]
1492+ r .UpdateState (resolver.State {Addresses :addrs })
1493+
1494+ // Ensure that no new connection is established.
1495+ for i := range holds {
1496+ sCtx ,sCancel := context .WithTimeout (ctx ,defaultTestShortTimeout )
1497+ defer sCancel ()
1498+ if holds [i ].Wait (sCtx ) {
1499+ t .Fatalf ("Unexpected connection attempt to backend: %s" ,addrs [i ])
1500+ }
1501+ }
1502+ if err := pickfirst .CheckRPCsToBackend (ctx ,cc ,addrs [1 ]);err != nil {
1503+ t .Fatal (err )
1504+ }
1505+ }
1506+
14271507// healthListenerCapturingCCWrapper is used to capture the health listener so
14281508// that health updates can be mocked for testing.
14291509type healthListenerCapturingCCWrapper struct {