@@ -129,6 +129,10 @@ public class ServerImplTest {
129129 .setRequestMarshaller (STRING_MARSHALLER )
130130 .setResponseMarshaller (INTEGER_MARSHALLER )
131131 .build ();
132+ private static final MethodDescriptor <String , Integer > GENERATED_METHOD =
133+ METHOD .toBuilder ()
134+ .setSampledToLocalTracing (true )
135+ .build ();
132136 private static final Context .Key <String > SERVER_ONLY = Context .key ("serverOnly" );
133137 private static final Context .Key <String > SERVER_TRACER_ADDED_KEY = Context .key ("tracer-added" );
134138 private static final Context .CancellableContext SERVER_CONTEXT =
@@ -142,6 +146,60 @@ public boolean shouldAccept(Runnable runnable) {
142146 };
143147 private static final String AUTHORITY = "some_authority" ;
144148
149+ private static final class MethodNameCapturingTracer extends ServerStreamTracer
150+ implements StatsTraceContext .ServerCallMethodListener {
151+ @ Nullable private ServerCallInfo <?, ?> serverCallInfo ;
152+ @ Nullable private String recordedMethodName ;
153+ @ Nullable private String resolvedMethodName ;
154+ private boolean streamClosed ;
155+
156+ @ Override
157+ public synchronized void serverCallMethodResolved (MethodDescriptor <?, ?> method ) {
158+ resolvedMethodName =
159+ recordMethodName (method .isSampledToLocalTracing (), method .getFullMethodName ());
160+ }
161+
162+ @ Override
163+ public synchronized void streamClosed (Status status ) {
164+ streamClosed = true ;
165+ if (serverCallInfo != null ) {
166+ recordedMethodName =
167+ recordMethodName (
168+ serverCallInfo .getMethodDescriptor ().isSampledToLocalTracing (),
169+ serverCallInfo .getMethodDescriptor ().getFullMethodName ());
170+ } else if (resolvedMethodName != null ) {
171+ recordedMethodName = resolvedMethodName ;
172+ } else {
173+ recordedMethodName = "other" ;
174+ }
175+ }
176+
177+ @ Override
178+ public synchronized void serverCallStarted (ServerCallInfo <?, ?> callInfo ) {
179+ serverCallInfo = callInfo ;
180+ if (streamClosed ) {
181+ recordedMethodName =
182+ recordMethodName (
183+ callInfo .getMethodDescriptor ().isSampledToLocalTracing (),
184+ callInfo .getMethodDescriptor ().getFullMethodName ());
185+ }
186+ }
187+
188+ @ Nullable
189+ synchronized ServerCallInfo <?, ?> getServerCallInfo () {
190+ return serverCallInfo ;
191+ }
192+
193+ @ Nullable
194+ synchronized String getRecordedMethodName () {
195+ return recordedMethodName ;
196+ }
197+
198+ private static String recordMethodName (boolean generatedMethod , String fullMethodName ) {
199+ return generatedMethod ? fullMethodName : "other" ;
200+ }
201+ }
202+
145203 @ Rule public final MockitoRule mocks = MockitoJUnit .rule ();
146204
147205 @ BeforeClass
@@ -462,6 +520,172 @@ public void methodNotFound() throws Exception {
462520 assertEquals (Status .Code .UNIMPLEMENTED , statusCaptor .getValue ().getCode ());
463521 }
464522
523+ @ Test
524+ public void primaryRegistryGeneratedMethod_streamClosedBeforeStart_preservesMethodName ()
525+ throws Exception {
526+ MethodNameCapturingTracer methodNameTracer = new MethodNameCapturingTracer ();
527+ streamTracerFactories =
528+ Collections .singletonList (
529+ new ServerStreamTracer .Factory () {
530+ @ Override
531+ public ServerStreamTracer newServerStreamTracer (
532+ String fullMethodName , Metadata headers ) {
533+ return methodNameTracer ;
534+ }
535+ });
536+ builder .addService (
537+ ServerServiceDefinition .builder (new ServiceDescriptor ("Waiter" , GENERATED_METHOD ))
538+ .addMethod (
539+ GENERATED_METHOD ,
540+ new ServerCallHandler <String , Integer >() {
541+ @ Override
542+ public ServerCall .Listener <String > startCall (
543+ ServerCall <String , Integer > call , Metadata headers ) {
544+ return callListener ;
545+ }
546+ })
547+ .build ());
548+
549+ createAndStartServer ();
550+ ServerTransportListener transportListener
551+ = transportServer .registerNewServerTransport (new SimpleServerTransport ());
552+ transportListener .transportReady (Attributes .EMPTY );
553+ Metadata requestHeaders = new Metadata ();
554+ StatsTraceContext statsTraceCtx =
555+ StatsTraceContext .newServerContext (
556+ streamTracerFactories , GENERATED_METHOD .getFullMethodName (), requestHeaders );
557+ when (stream .getAttributes ()).thenReturn (Attributes .EMPTY );
558+ when (stream .statsTraceContext ()).thenReturn (statsTraceCtx );
559+
560+ transportListener .streamCreated (stream , GENERATED_METHOD .getFullMethodName (), requestHeaders );
561+ verify (stream ).setListener (isA (ServerStreamListener .class ));
562+ verify (stream , atLeast (1 )).statsTraceContext ();
563+
564+ statsTraceCtx .streamClosed (Status .CANCELLED );
565+ assertNull (methodNameTracer .getServerCallInfo ());
566+ assertEquals (
567+ GENERATED_METHOD .getFullMethodName (),
568+ methodNameTracer .getRecordedMethodName ());
569+
570+ assertEquals (1 , executor .runDueTasks ());
571+
572+ assertNotNull (methodNameTracer .getServerCallInfo ());
573+ assertSame (GENERATED_METHOD , methodNameTracer .getServerCallInfo ().getMethodDescriptor ());
574+ assertEquals (
575+ GENERATED_METHOD .getFullMethodName (),
576+ methodNameTracer .getRecordedMethodName ());
577+ verify (fallbackRegistry , never ()).lookupMethod (anyString (), any ());
578+ }
579+
580+ @ Test
581+ public void primaryRegistryNonGeneratedMethod_streamClosedBeforeStart_recordsOther ()
582+ throws Exception {
583+ MethodNameCapturingTracer methodNameTracer = new MethodNameCapturingTracer ();
584+ streamTracerFactories =
585+ Collections .singletonList (
586+ new ServerStreamTracer .Factory () {
587+ @ Override
588+ public ServerStreamTracer newServerStreamTracer (
589+ String fullMethodName , Metadata headers ) {
590+ return methodNameTracer ;
591+ }
592+ });
593+ builder .addService (
594+ ServerServiceDefinition .builder (new ServiceDescriptor ("Waiter" , METHOD ))
595+ .addMethod (
596+ METHOD ,
597+ new ServerCallHandler <String , Integer >() {
598+ @ Override
599+ public ServerCall .Listener <String > startCall (
600+ ServerCall <String , Integer > call , Metadata headers ) {
601+ return callListener ;
602+ }
603+ })
604+ .build ());
605+
606+ createAndStartServer ();
607+ ServerTransportListener transportListener
608+ = transportServer .registerNewServerTransport (new SimpleServerTransport ());
609+ transportListener .transportReady (Attributes .EMPTY );
610+ Metadata requestHeaders = new Metadata ();
611+ StatsTraceContext statsTraceCtx =
612+ StatsTraceContext .newServerContext (
613+ streamTracerFactories , METHOD .getFullMethodName (), requestHeaders );
614+ when (stream .getAttributes ()).thenReturn (Attributes .EMPTY );
615+ when (stream .statsTraceContext ()).thenReturn (statsTraceCtx );
616+
617+ transportListener .streamCreated (stream , METHOD .getFullMethodName (), requestHeaders );
618+ verify (stream ).setListener (isA (ServerStreamListener .class ));
619+ verify (stream , atLeast (1 )).statsTraceContext ();
620+
621+ statsTraceCtx .streamClosed (Status .CANCELLED );
622+ assertNull (methodNameTracer .getServerCallInfo ());
623+ assertEquals ("other" , methodNameTracer .getRecordedMethodName ());
624+
625+ assertEquals (1 , executor .runDueTasks ());
626+
627+ assertNotNull (methodNameTracer .getServerCallInfo ());
628+ assertSame (METHOD , methodNameTracer .getServerCallInfo ().getMethodDescriptor ());
629+ assertEquals ("other" , methodNameTracer .getRecordedMethodName ());
630+ verify (fallbackRegistry , never ()).lookupMethod (anyString (), any ());
631+ }
632+
633+ @ Test
634+ public void fallbackRegistryGeneratedMethod_streamClosedBeforeStart_resolvesOnAsyncLookup ()
635+ throws Exception {
636+ MethodNameCapturingTracer methodNameTracer = new MethodNameCapturingTracer ();
637+ streamTracerFactories =
638+ Collections .singletonList (
639+ new ServerStreamTracer .Factory () {
640+ @ Override
641+ public ServerStreamTracer newServerStreamTracer (
642+ String fullMethodName , Metadata headers ) {
643+ return methodNameTracer ;
644+ }
645+ });
646+ mutableFallbackRegistry .addService (
647+ ServerServiceDefinition .builder (new ServiceDescriptor ("Waiter" , GENERATED_METHOD ))
648+ .addMethod (
649+ GENERATED_METHOD ,
650+ new ServerCallHandler <String , Integer >() {
651+ @ Override
652+ public ServerCall .Listener <String > startCall (
653+ ServerCall <String , Integer > call , Metadata headers ) {
654+ return callListener ;
655+ }
656+ })
657+ .build ());
658+
659+ createAndStartServer ();
660+ ServerTransportListener transportListener
661+ = transportServer .registerNewServerTransport (new SimpleServerTransport ());
662+ transportListener .transportReady (Attributes .EMPTY );
663+ Metadata requestHeaders = new Metadata ();
664+ StatsTraceContext statsTraceCtx =
665+ StatsTraceContext .newServerContext (
666+ streamTracerFactories , GENERATED_METHOD .getFullMethodName (), requestHeaders );
667+ when (stream .getAttributes ()).thenReturn (Attributes .EMPTY );
668+ when (stream .statsTraceContext ()).thenReturn (statsTraceCtx );
669+
670+ transportListener .streamCreated (stream , GENERATED_METHOD .getFullMethodName (), requestHeaders );
671+ verify (stream ).setListener (isA (ServerStreamListener .class ));
672+ verify (stream , atLeast (1 )).statsTraceContext ();
673+
674+ statsTraceCtx .streamClosed (Status .CANCELLED );
675+ assertNull (methodNameTracer .getServerCallInfo ());
676+ assertEquals ("other" , methodNameTracer .getRecordedMethodName ());
677+ verify (fallbackRegistry , never ()).lookupMethod (anyString (), any ());
678+
679+ assertEquals (1 , executor .runDueTasks ());
680+
681+ assertNotNull (methodNameTracer .getServerCallInfo ());
682+ assertSame (GENERATED_METHOD , methodNameTracer .getServerCallInfo ().getMethodDescriptor ());
683+ assertEquals (
684+ GENERATED_METHOD .getFullMethodName (),
685+ methodNameTracer .getRecordedMethodName ());
686+ verify (fallbackRegistry ).lookupMethod (GENERATED_METHOD .getFullMethodName (), AUTHORITY );
687+ }
688+
465689
466690 @ Test
467691 public void executorSupplierSameExecutorBasic () throws Exception {
0 commit comments