8282import io .grpc .inprocess .InProcessServerBuilder ;
8383import io .grpc .internal .BackoffPolicy ;
8484import io .grpc .internal .FakeClock ;
85+ import io .grpc .internal .PickFirstLoadBalancerProvider ;
8586import io .grpc .lb .v1 .ClientStats ;
8687import io .grpc .lb .v1 .ClientStatsPerToken ;
8788import io .grpc .lb .v1 .FallbackResponse ;
@@ -1921,10 +1922,16 @@ public void grpclbWorking_pickFirstMode() throws Exception {
19211922 // With delegation, the child pick_first creates the subchannel
19221923 inOrder .verify (helper ).createSubchannel (createSubchannelArgsCaptor .capture ());
19231924 CreateSubchannelArgs createSubchannelArgs = createSubchannelArgsCaptor .getValue ();
1924- assertThat (createSubchannelArgs .getAddresses ())
1925- .containsExactly (
1926- new EquivalentAddressGroup (backends1 .get (0 ).addr , eagAttrsWithToken ("token0001" )),
1927- new EquivalentAddressGroup (backends1 .get (1 ).addr , eagAttrsWithToken ("token0002" )));
1925+ if (PickFirstLoadBalancerProvider .isEnabledNewPickFirst ()) {
1926+ assertThat (createSubchannelArgs .getAddresses ())
1927+ .containsExactly (
1928+ new EquivalentAddressGroup (backends1 .get (0 ).addr , eagAttrsWithToken ("token0001" )));
1929+ } else {
1930+ assertThat (createSubchannelArgs .getAddresses ())
1931+ .containsExactly (
1932+ new EquivalentAddressGroup (backends1 .get (0 ).addr , eagAttrsWithToken ("token0001" )),
1933+ new EquivalentAddressGroup (backends1 .get (1 ).addr , eagAttrsWithToken ("token0002" )));
1934+ }
19281935
19291936 // Child pick_first eagerly connects, so we start in CONNECTING
19301937 inOrder .verify (helper , atLeast (1 )).updateBalancingState (eq (CONNECTING ), pickerCaptor .capture ());
@@ -1939,18 +1946,20 @@ public void grpclbWorking_pickFirstMode() throws Exception {
19391946 // Child pick_first eagerly calls requestConnection()
19401947 verify (subchannel ).requestConnection ();
19411948
1942- // TRANSIENT_FAILURE
1943- Status error = Status .UNAVAILABLE .withDescription ("Simulated connection error" );
1944- deliverSubchannelState (subchannel , ConnectivityStateInfo .forTransientFailure (error ));
1945- // The child LB will notify our helper, which updates grpclb state
1946- inOrder .verify (helper , atLeast (1 ))
1947- .updateBalancingState (eq (TRANSIENT_FAILURE ), pickerCaptor .capture ());
1948- RoundRobinPicker picker1 = (RoundRobinPicker ) pickerCaptor .getValue ();
1949- assertThat (picker1 .dropList ).containsExactly (null , null );
1950- ChildLbPickerEntry failureEntry = (ChildLbPickerEntry ) picker1 .pickList .get (0 );
1951- PickResult failureResult =
1952- failureEntry .getChildPicker ().pickSubchannel (mock (PickSubchannelArgs .class ));
1953- assertThat (failureResult .getStatus ()).isEqualTo (error );
1949+ if (!PickFirstLoadBalancerProvider .isEnabledNewPickFirst ()) {
1950+ // TRANSIENT_FAILURE
1951+ Status error = Status .UNAVAILABLE .withDescription ("Simulated connection error" );
1952+ deliverSubchannelState (subchannel , ConnectivityStateInfo .forTransientFailure (error ));
1953+ // The child LB will notify our helper, which updates grpclb state
1954+ inOrder .verify (helper , atLeast (1 ))
1955+ .updateBalancingState (eq (TRANSIENT_FAILURE ), pickerCaptor .capture ());
1956+ RoundRobinPicker picker1 = (RoundRobinPicker ) pickerCaptor .getValue ();
1957+ assertThat (picker1 .dropList ).containsExactly (null , null );
1958+ ChildLbPickerEntry failureEntry = (ChildLbPickerEntry ) picker1 .pickList .get (0 );
1959+ PickResult failureResult =
1960+ failureEntry .getChildPicker ().pickSubchannel (mock (PickSubchannelArgs .class ));
1961+ assertThat (failureResult .getStatus ()).isEqualTo (error );
1962+ }
19541963
19551964 // READY
19561965 deliverSubchannelState (subchannel , ConnectivityStateInfo .forNonError (READY ));
@@ -1977,11 +1986,15 @@ public void grpclbWorking_pickFirstMode() throws Exception {
19771986 assertThat (mockSubchannels ).isEmpty ();
19781987
19791988 // The child LB policy internally calls updateAddresses on the subchannel
1980- verify (subchannel ).updateAddresses (
1981- eq (Arrays .asList (
1982- new EquivalentAddressGroup (backends2 .get (0 ).addr , eagAttrsWithToken ("token0001" )),
1983- new EquivalentAddressGroup (backends2 .get (2 ).addr ,
1984- eagAttrsWithToken ("token0004" )))));
1989+ List <EquivalentAddressGroup > expectedAddresses =
1990+ PickFirstLoadBalancerProvider .isEnabledNewPickFirst ()
1991+ ? Collections .singletonList (
1992+ new EquivalentAddressGroup (backends2 .get (0 ).addr , eagAttrsWithToken ("token0001" )))
1993+ : Arrays .asList (
1994+ new EquivalentAddressGroup (backends2 .get (0 ).addr , eagAttrsWithToken ("token0001" )),
1995+ new EquivalentAddressGroup (backends2 .get (2 ).addr ,
1996+ eagAttrsWithToken ("token0004" )));
1997+ verify (subchannel ).updateAddresses (eq (expectedAddresses ));
19851998 inOrder .verify (helper , atLeast (1 )).updateBalancingState (eq (READY ), pickerCaptor .capture ());
19861999 RoundRobinPicker picker3 = (RoundRobinPicker ) pickerCaptor .getValue ();
19872000 assertThat (picker3 .dropList ).containsExactly (
@@ -2004,7 +2017,8 @@ public void grpclbWorking_pickFirstMode() throws Exception {
20042017 assertThat (pick .getSubchannel ()).isNull ();
20052018 verify (subchannel , times (2 )).requestConnection ();
20062019 balancer .requestConnection ();
2007- verify (subchannel , times (3 )).requestConnection ();
2020+ int expectedRequests = PickFirstLoadBalancerProvider .isEnabledNewPickFirst () ? 2 : 3 ;
2021+ verify (subchannel , times (expectedRequests )).requestConnection ();
20082022
20092023 // PICK_FIRST doesn't use subchannelPool
20102024 verify (subchannelPool , never ())
@@ -2045,10 +2059,16 @@ public void grpclbWorking_pickFirstMode_lbSendsEmptyAddress() throws Exception {
20452059 // The child pick_first creates the first subchannel
20462060 inOrder .verify (helper ).createSubchannel (createSubchannelArgsCaptor .capture ());
20472061 CreateSubchannelArgs createSubchannelArgs = createSubchannelArgsCaptor .getValue ();
2048- assertThat (createSubchannelArgs .getAddresses ())
2049- .containsExactly (
2050- new EquivalentAddressGroup (backends1 .get (0 ).addr , eagAttrsWithToken ("token0001" )),
2051- new EquivalentAddressGroup (backends1 .get (1 ).addr , eagAttrsWithToken ("token0002" )));
2062+ if (PickFirstLoadBalancerProvider .isEnabledNewPickFirst ()) {
2063+ assertThat (createSubchannelArgs .getAddresses ())
2064+ .containsExactly (
2065+ new EquivalentAddressGroup (backends1 .get (0 ).addr , eagAttrsWithToken ("token0001" )));
2066+ } else {
2067+ assertThat (createSubchannelArgs .getAddresses ())
2068+ .containsExactly (
2069+ new EquivalentAddressGroup (backends1 .get (0 ).addr , eagAttrsWithToken ("token0001" )),
2070+ new EquivalentAddressGroup (backends1 .get (1 ).addr , eagAttrsWithToken ("token0002" )));
2071+ }
20522072
20532073 // Child pick_first eagerly connects, so initial state is CONNECTING
20542074 inOrder .verify (helper , atLeast (1 )).updateBalancingState (eq (CONNECTING ), pickerCaptor .capture ());
@@ -2104,7 +2124,18 @@ public void grpclbWorking_pickFirstMode_lbSendsEmptyAddress() throws Exception {
21042124 lbResponseObserver .onNext (buildLbResponse (backends2 ));
21052125
21062126 // A NEW child LB and NEW subchannel are created upon recovery
2107- inOrder .verify (helper ).createSubchannel (any (CreateSubchannelArgs .class ));
2127+ inOrder .verify (helper ).createSubchannel (createSubchannelArgsCaptor .capture ());
2128+ CreateSubchannelArgs createSubchannelArgs2 = createSubchannelArgsCaptor .getValue ();
2129+ if (PickFirstLoadBalancerProvider .isEnabledNewPickFirst ()) {
2130+ assertThat (createSubchannelArgs2 .getAddresses ())
2131+ .containsExactly (
2132+ new EquivalentAddressGroup (backends2 .get (0 ).addr , eagAttrsWithToken ("token0001" )));
2133+ } else {
2134+ assertThat (createSubchannelArgs2 .getAddresses ())
2135+ .containsExactly (
2136+ new EquivalentAddressGroup (backends2 .get (0 ).addr , eagAttrsWithToken ("token0001" )),
2137+ new EquivalentAddressGroup (backends2 .get (2 ).addr , eagAttrsWithToken ("token0004" )));
2138+ }
21082139 assertThat (mockSubchannels ).hasSize (1 );
21092140 Subchannel subchannel2 = mockSubchannels .poll ();
21102141 inOrder .verify (helper , atLeast (1 )).updateBalancingState (eq (CONNECTING ), pickerCaptor .capture ());
@@ -2180,8 +2211,13 @@ private void pickFirstModeFallback(long timeout) throws Exception {
21802211 // Entering fallback mode - child LB is created for fallback backends
21812212 inOrder .verify (helper ).createSubchannel (createSubchannelArgsCaptor .capture ());
21822213 CreateSubchannelArgs createSubchannelArgs = createSubchannelArgsCaptor .getValue ();
2183- assertThat (createSubchannelArgs .getAddresses ())
2184- .containsExactly (backendList .get (0 ), backendList .get (1 ));
2214+ if (PickFirstLoadBalancerProvider .isEnabledNewPickFirst ()) {
2215+ assertThat (createSubchannelArgs .getAddresses ())
2216+ .containsExactly (backendList .get (0 ));
2217+ } else {
2218+ assertThat (createSubchannelArgs .getAddresses ())
2219+ .containsExactly (backendList .get (0 ), backendList .get (1 ));
2220+ }
21852221
21862222 assertThat (mockSubchannels ).hasSize (1 );
21872223 Subchannel subchannel = mockSubchannels .poll ();
@@ -2212,16 +2248,44 @@ private void pickFirstModeFallback(long timeout) throws Exception {
22122248 lbResponseObserver .onNext (buildInitialResponse ());
22132249 lbResponseObserver .onNext (buildLbResponse (backends1 ));
22142250
2215- // subchannel should be updated, NOT recreated
2216- inOrder .verify (helper , never ()).createSubchannel (any (CreateSubchannelArgs .class ));
2217- assertThat (mockSubchannels ).isEmpty ();
2218- // The child LB internally calls updateAddresses on the existing subchannel
2219- verify (subchannel ).updateAddresses (
2220- eq (Arrays .asList (
2221- new EquivalentAddressGroup (backends1 .get (0 ).addr , eagAttrsWithToken ("token0001" )),
2222- new EquivalentAddressGroup (backends1 .get (1 ).addr ,
2223- eagAttrsWithToken ("token0002" )))));
2224- inOrder .verify (helper , atLeast (1 )).updateBalancingState (eq (READY ), pickerCaptor .capture ());
2251+ if (PickFirstLoadBalancerProvider .isEnabledNewPickFirst ()) {
2252+ // In new PF, active fallback subchannel is shut down because its address is not in backends1
2253+ verify (subchannel ).shutdown ();
2254+ // And LB state transitions to IDLE with RequestConnectionPicker
2255+ inOrder .verify (helper , atLeast (1 )).updateBalancingState (eq (IDLE ), pickerCaptor .capture ());
2256+ RoundRobinPicker pickerIdle = (RoundRobinPicker ) pickerCaptor .getValue ();
2257+ ChildLbPickerEntry idleEntry = (ChildLbPickerEntry ) pickerIdle .pickList .get (0 );
2258+
2259+ // Picking while IDLE triggers requestConnection(), creating a subchannel for backends1.get(0)
2260+ PickSubchannelArgs args = mock (PickSubchannelArgs .class );
2261+ PickResult pick = idleEntry .getChildPicker ().pickSubchannel (args );
2262+ assertThat (pick .getSubchannel ()).isNull (); // BUFFERing while IDLE
2263+
2264+ inOrder .verify (helper ).createSubchannel (createSubchannelArgsCaptor .capture ());
2265+ CreateSubchannelArgs createSubchannelArgs2 = createSubchannelArgsCaptor .getValue ();
2266+ assertThat (createSubchannelArgs2 .getAddresses ())
2267+ .containsExactly (
2268+ new EquivalentAddressGroup (backends1 .get (0 ).addr , eagAttrsWithToken ("token0001" )));
2269+ assertThat (mockSubchannels ).hasSize (1 );
2270+ subchannel = mockSubchannels .poll ();
2271+ verify (subchannel ).requestConnection ();
2272+
2273+ // subchannel becomes READY
2274+ deliverSubchannelState (subchannel , ConnectivityStateInfo .forNonError (READY ));
2275+ inOrder .verify (helper , atLeast (1 )).updateBalancingState (eq (READY ), pickerCaptor .capture ());
2276+ } else {
2277+ // subchannel should be updated, NOT recreated
2278+ inOrder .verify (helper , never ()).createSubchannel (any (CreateSubchannelArgs .class ));
2279+ assertThat (mockSubchannels ).isEmpty ();
2280+ // The child LB internally calls updateAddresses on the existing subchannel
2281+ verify (subchannel ).updateAddresses (
2282+ eq (Arrays .asList (
2283+ new EquivalentAddressGroup (backends1 .get (0 ).addr , eagAttrsWithToken ("token0001" )),
2284+ new EquivalentAddressGroup (backends1 .get (1 ).addr ,
2285+ eagAttrsWithToken ("token0002" )))));
2286+ inOrder .verify (helper , atLeast (1 )).updateBalancingState (eq (READY ), pickerCaptor .capture ());
2287+ }
2288+
22252289 RoundRobinPicker picker2 = (RoundRobinPicker ) pickerCaptor .getValue ();
22262290 assertThat (picker2 .dropList ).containsExactly (null , null );
22272291
@@ -2247,7 +2311,8 @@ private void pickFirstModeFallback(long timeout) throws Exception {
22472311 verify (subchannel , times (2 )).requestConnection ();
22482312
22492313 balancer .requestConnection ();
2250- verify (subchannel , times (3 )).requestConnection ();
2314+ int expectedRequests = PickFirstLoadBalancerProvider .isEnabledNewPickFirst () ? 2 : 3 ;
2315+ verify (subchannel , times (expectedRequests )).requestConnection ();
22512316
22522317 // PICK_FIRST doesn't use subchannelPool
22532318 verify (subchannelPool , never ())
@@ -2334,10 +2399,16 @@ public void switchMode() throws Exception {
23342399 // PICK_FIRST Subchannel: child LB creates it
23352400 inOrder .verify (helper ).createSubchannel (createSubchannelArgsCaptor .capture ());
23362401 CreateSubchannelArgs createSubchannelArgs = createSubchannelArgsCaptor .getValue ();
2337- assertThat (createSubchannelArgs .getAddresses ())
2338- .containsExactly (
2339- new EquivalentAddressGroup (backends1 .get (0 ).addr , eagAttrsWithToken ("token0001" )),
2340- new EquivalentAddressGroup (backends1 .get (1 ).addr , eagAttrsWithToken ("token0002" )));
2402+ if (PickFirstLoadBalancerProvider .isEnabledNewPickFirst ()) {
2403+ assertThat (createSubchannelArgs .getAddresses ())
2404+ .containsExactly (
2405+ new EquivalentAddressGroup (backends1 .get (0 ).addr , eagAttrsWithToken ("token0001" )));
2406+ } else {
2407+ assertThat (createSubchannelArgs .getAddresses ())
2408+ .containsExactly (
2409+ new EquivalentAddressGroup (backends1 .get (0 ).addr , eagAttrsWithToken ("token0001" )),
2410+ new EquivalentAddressGroup (backends1 .get (1 ).addr , eagAttrsWithToken ("token0002" )));
2411+ }
23412412
23422413 // Child pick_first eagerly connects, so initial state is CONNECTING (not IDLE)
23432414 inOrder .verify (helper , atLeast (1 ))
@@ -2424,10 +2495,16 @@ public void switchMode_nullLbPolicy() throws Exception {
24242495 // PICK_FIRST Subchannel: with delegation, child LB creates the subchannel
24252496 inOrder .verify (helper ).createSubchannel (createSubchannelArgsCaptor .capture ());
24262497 CreateSubchannelArgs createSubchannelArgs = createSubchannelArgsCaptor .getValue ();
2427- assertThat (createSubchannelArgs .getAddresses ())
2428- .containsExactly (
2429- new EquivalentAddressGroup (backends1 .get (0 ).addr , eagAttrsWithToken ("token0001" )),
2430- new EquivalentAddressGroup (backends1 .get (1 ).addr , eagAttrsWithToken ("token0002" )));
2498+ if (PickFirstLoadBalancerProvider .isEnabledNewPickFirst ()) {
2499+ assertThat (createSubchannelArgs .getAddresses ())
2500+ .containsExactly (
2501+ new EquivalentAddressGroup (backends1 .get (0 ).addr , eagAttrsWithToken ("token0001" )));
2502+ } else {
2503+ assertThat (createSubchannelArgs .getAddresses ())
2504+ .containsExactly (
2505+ new EquivalentAddressGroup (backends1 .get (0 ).addr , eagAttrsWithToken ("token0001" )),
2506+ new EquivalentAddressGroup (backends1 .get (1 ).addr , eagAttrsWithToken ("token0002" )));
2507+ }
24312508
24322509 // Child pick_first eagerly connects, so state is CONNECTING (not IDLE)
24332510 inOrder .verify (helper , atLeast (1 ))
0 commit comments