@@ -260,17 +260,17 @@ public void pickAfterStateChangeAfterResolution() throws Exception {
260260 reset (mockHelper );
261261 when (mockHelper .getSynchronizationContext ()).thenReturn (syncContext );
262262
263+ stateListener .onSubchannelState (ConnectivityStateInfo .forNonError (IDLE ));
264+ inOrder .verify (mockHelper ).refreshNameResolution ();
265+ inOrder .verify (mockHelper ).updateBalancingState (eq (IDLE ), pickerCaptor .capture ());
266+ assertEquals (Status .OK , pickerCaptor .getValue ().pickSubchannel (mockArgs ).getStatus ());
267+
263268 Status error = Status .UNAVAILABLE .withDescription ("boom!" );
264269 stateListener .onSubchannelState (ConnectivityStateInfo .forTransientFailure (error ));
265270 inOrder .verify (mockHelper ).refreshNameResolution ();
266271 inOrder .verify (mockHelper ).updateBalancingState (eq (TRANSIENT_FAILURE ), pickerCaptor .capture ());
267272 assertEquals (error , pickerCaptor .getValue ().pickSubchannel (mockArgs ).getStatus ());
268273
269- stateListener .onSubchannelState (ConnectivityStateInfo .forNonError (IDLE ));
270- inOrder .verify (mockHelper ).refreshNameResolution ();
271- inOrder .verify (mockHelper ).updateBalancingState (eq (IDLE ), pickerCaptor .capture ());
272- assertEquals (Status .OK , pickerCaptor .getValue ().pickSubchannel (mockArgs ).getStatus ());
273-
274274 stateListener .onSubchannelState (ConnectivityStateInfo .forNonError (READY ));
275275 inOrder .verify (mockHelper ).updateBalancingState (eq (READY ), pickerCaptor .capture ());
276276 assertEquals (subchannel , pickerCaptor .getValue ().pickSubchannel (mockArgs ).getSubchannel ());
@@ -279,6 +279,43 @@ public void pickAfterStateChangeAfterResolution() throws Exception {
279279 verifyNoMoreInteractions (mockHelper );
280280 }
281281
282+ @ Test
283+ public void pickAfterResolutionAfterTransientValue () throws Exception {
284+ InOrder inOrder = inOrder (mockHelper );
285+
286+ loadBalancer .acceptResolvedAddresses (
287+ ResolvedAddresses .newBuilder ().setAddresses (servers ).setAttributes (affinity ).build ());
288+ inOrder .verify (mockHelper ).createSubchannel (createArgsCaptor .capture ());
289+ CreateSubchannelArgs args = createArgsCaptor .getValue ();
290+ assertThat (args .getAddresses ()).isEqualTo (servers );
291+ verify (mockSubchannel ).start (stateListenerCaptor .capture ());
292+ SubchannelStateListener stateListener = stateListenerCaptor .getValue ();
293+ verify (mockHelper ).updateBalancingState (eq (CONNECTING ), pickerCaptor .capture ());
294+ verify (mockSubchannel ).requestConnection ();
295+ reset (mockHelper );
296+ when (mockHelper .getSynchronizationContext ()).thenReturn (syncContext );
297+
298+ // An error has happened.
299+ Status error = Status .UNAVAILABLE .withDescription ("boom!" );
300+ stateListener .onSubchannelState (ConnectivityStateInfo .forTransientFailure (error ));
301+ inOrder .verify (mockHelper ).refreshNameResolution ();
302+ inOrder .verify (mockHelper ).updateBalancingState (eq (TRANSIENT_FAILURE ), pickerCaptor .capture ());
303+ assertEquals (error , pickerCaptor .getValue ().pickSubchannel (mockArgs ).getStatus ());
304+
305+ // But a subsequent IDLE update should be ignored and the LB state not updated. Additionally,
306+ // a request for a new connection should be made keep the subchannel trying to connect.
307+ stateListener .onSubchannelState (ConnectivityStateInfo .forNonError (IDLE ));
308+ inOrder .verify (mockHelper ).refreshNameResolution ();
309+ verifyNoMoreInteractions (mockHelper );
310+ assertEquals (error , pickerCaptor .getValue ().pickSubchannel (mockArgs ).getStatus ());
311+ verify (mockSubchannel , times (2 )).requestConnection ();
312+
313+ // Transition from TRANSIENT_ERROR to CONNECTING should also be ignored.
314+ stateListener .onSubchannelState (ConnectivityStateInfo .forNonError (CONNECTING ));
315+ verifyNoMoreInteractions (mockHelper );
316+ assertEquals (error , pickerCaptor .getValue ().pickSubchannel (mockArgs ).getStatus ());
317+ }
318+
282319 @ Test
283320 public void nameResolutionError () throws Exception {
284321 Status error = Status .NOT_FOUND .withDescription ("nameResolutionError" );
0 commit comments