@@ -845,6 +845,83 @@ public void streamDelayMetrics_shutdownNow() {
845845 verify (mockTracer ).delayEnded ();
846846 }
847847
848+ @ Test
849+ public void streamDelayMetrics_cadenceReasonUpdate_doesNotStartNewTypeSegment () {
850+ ClientStreamTracer mockTracer = mock (ClientStreamTracer .class );
851+ ClientStreamTracer [] customTracers = new ClientStreamTracer [] { mockTracer };
852+
853+ SubchannelPicker picker1 = mock (SubchannelPicker .class );
854+ when (picker1 .pickSubchannel (any (PickSubchannelArgs .class )))
855+ .thenReturn (PickResult .withNoResult ("connecting" , "attempt 1" ));
856+
857+ delayedTransport .reprocess (picker1 );
858+ delayedTransport .newStream (method , headers , callOptions , customTracers );
859+
860+ verify (mockTracer , times (1 )).delayTypeStarted ("connecting" );
861+ verify (mockTracer ).delayReasonAttached ("attempt 1" );
862+
863+ SubchannelPicker picker2 = mock (SubchannelPicker .class );
864+ when (picker2 .pickSubchannel (any (PickSubchannelArgs .class )))
865+ .thenReturn (PickResult .withNoResult ("connecting" , "attempt 2" ));
866+
867+ delayedTransport .reprocess (picker2 );
868+
869+ verify (mockTracer , times (1 )).delayTypeStarted ("connecting" );
870+ verify (mockTracer ).delayReasonAttached ("attempt 2" );
871+ verify (mockTracer , never ()).delayEnded ();
872+ }
873+
874+ @ Test
875+ public void streamDelayMetrics_channelFallback_clientChannelInit () {
876+ ClientStreamTracer mockTracer = mock (ClientStreamTracer .class );
877+ ClientStreamTracer [] customTracers = new ClientStreamTracer [] { mockTracer };
878+
879+ // No picker reprocessed yet (lastPicker == null)
880+ delayedTransport .newStream (method , headers , callOptions , customTracers );
881+
882+ verify (mockTracer ).delayTypeStarted ("client_channel_init" );
883+ verify (mockTracer ).delayReasonAttached ("client channel: created LB policy." );
884+ }
885+
886+ @ Test
887+ public void streamDelayMetrics_channelFallback_subchannelStateMismatch () {
888+ ClientStreamTracer mockTracer = mock (ClientStreamTracer .class );
889+ ClientStreamTracer [] customTracers = new ClientStreamTracer [] { mockTracer };
890+
891+ io .grpc .LoadBalancer .Subchannel disconnectedSubchannel = mock (io .grpc .LoadBalancer .Subchannel .class );
892+ when (disconnectedSubchannel .getInternalSubchannel ())
893+ .thenReturn (newTransportProvider (null ));
894+
895+ SubchannelPicker stalePicker = mock (SubchannelPicker .class );
896+ when (stalePicker .pickSubchannel (any (PickSubchannelArgs .class )))
897+ .thenReturn (PickResult .withSubchannel (disconnectedSubchannel ));
898+
899+ delayedTransport .reprocess (stalePicker );
900+ delayedTransport .newStream (method , headers , callOptions , customTracers );
901+
902+ verify (mockTracer ).delayTypeStarted ("subchannel_state_mismatch" );
903+ verify (mockTracer ).delayReasonAttached (
904+ "subchannel returned by LB picker has no connected subchannel" );
905+ }
906+
907+ @ Test
908+ public void streamDelayMetrics_channelFallback_waitForReadyFailed () {
909+ ClientStreamTracer mockTracer = mock (ClientStreamTracer .class );
910+ ClientStreamTracer [] customTracers = new ClientStreamTracer [] { mockTracer };
911+
912+ SubchannelPicker failPicker = mock (SubchannelPicker .class );
913+ when (failPicker .pickSubchannel (any (PickSubchannelArgs .class )))
914+ .thenReturn (PickResult .withError (Status .UNAVAILABLE ));
915+
916+ delayedTransport .reprocess (failPicker );
917+ CallOptions wfrOptions = callOptions .withWaitForReady ();
918+ delayedTransport .newStream (method , headers , wfrOptions , customTracers );
919+
920+ verify (mockTracer ).delayTypeStarted ("wait_for_ready_failed" );
921+ verify (mockTracer ).delayReasonAttached (
922+ "wait_for_ready RPC failed with status: " + Status .UNAVAILABLE );
923+ }
924+
848925 private static TransportProvider newTransportProvider (final ClientTransport transport ) {
849926 return new TransportProvider () {
850927 @ Override
0 commit comments