@@ -279,21 +279,61 @@ public void pickAfterStateChange() throws Exception {
279279 Status error = Status .UNKNOWN .withDescription ("¯\\ _(ツ)_//¯" );
280280 deliverSubchannelState (subchannel ,
281281 ConnectivityStateInfo .forTransientFailure (error ));
282- assertThat (subchannelStateInfo .value ) .isEqualTo (
283- ConnectivityStateInfo . forTransientFailure ( error ) );
282+ assertThat (subchannelStateInfo .value . getState ()) .isEqualTo (TRANSIENT_FAILURE );
283+ assertThat ( subchannelStateInfo . value . getStatus ()). isEqualTo ( error );
284284 inOrder .verify (mockHelper ).updateBalancingState (eq (CONNECTING ), pickerCaptor .capture ());
285285 assertThat (pickerCaptor .getValue ()).isInstanceOf (EmptyPicker .class );
286286
287287 deliverSubchannelState (subchannel ,
288288 ConnectivityStateInfo .forNonError (IDLE ));
289- assertThat (subchannelStateInfo .value ) .isEqualTo (
290- ConnectivityStateInfo . forNonError ( IDLE ) );
289+ assertThat (subchannelStateInfo .value . getState ()) .isEqualTo (TRANSIENT_FAILURE );
290+ assertThat ( subchannelStateInfo . value . getStatus ()). isEqualTo ( error );
291291
292292 verify (subchannel , times (2 )).requestConnection ();
293293 verify (mockHelper , times (3 )).createSubchannel (any (CreateSubchannelArgs .class ));
294294 verifyNoMoreInteractions (mockHelper );
295295 }
296296
297+ @ Test
298+ public void stayTransientFailureUntilReady () {
299+ InOrder inOrder = inOrder (mockHelper );
300+ loadBalancer .handleResolvedAddresses (
301+ ResolvedAddresses .newBuilder ().setAddresses (servers ).setAttributes (Attributes .EMPTY )
302+ .build ());
303+
304+ inOrder .verify (mockHelper ).updateBalancingState (eq (CONNECTING ), isA (EmptyPicker .class ));
305+
306+ // Simulate state transitions for each subchannel individually.
307+ for (Subchannel sc : loadBalancer .getSubchannels ()) {
308+ Status error = Status .UNKNOWN .withDescription ("connection broken" );
309+ deliverSubchannelState (
310+ sc ,
311+ ConnectivityStateInfo .forTransientFailure (error ));
312+ deliverSubchannelState (
313+ sc ,
314+ ConnectivityStateInfo .forNonError (IDLE ));
315+ deliverSubchannelState (
316+ sc ,
317+ ConnectivityStateInfo .forNonError (CONNECTING ));
318+ Ref <ConnectivityStateInfo > scStateInfo = sc .getAttributes ().get (
319+ STATE_INFO );
320+ assertThat (scStateInfo .value .getState ()).isEqualTo (TRANSIENT_FAILURE );
321+ assertThat (scStateInfo .value .getStatus ()).isEqualTo (error );
322+ }
323+ inOrder .verify (mockHelper ).updateBalancingState (eq (TRANSIENT_FAILURE ), isA (EmptyPicker .class ));
324+ inOrder .verifyNoMoreInteractions ();
325+
326+ Subchannel subchannel = loadBalancer .getSubchannels ().iterator ().next ();
327+ deliverSubchannelState (subchannel , ConnectivityStateInfo .forNonError (READY ));
328+ Ref <ConnectivityStateInfo > subchannelStateInfo = subchannel .getAttributes ().get (
329+ STATE_INFO );
330+ assertThat (subchannelStateInfo .value ).isEqualTo (ConnectivityStateInfo .forNonError (READY ));
331+ inOrder .verify (mockHelper ).updateBalancingState (eq (READY ), isA (ReadyPicker .class ));
332+
333+ verify (mockHelper , times (3 )).createSubchannel (any (CreateSubchannelArgs .class ));
334+ verifyNoMoreInteractions (mockHelper );
335+ }
336+
297337 @ Test
298338 public void pickerRoundRobin () throws Exception {
299339 Subchannel subchannel = mock (Subchannel .class );
0 commit comments