From c922f71775cd6d56c2dad6654c7043f8754c5eb4 Mon Sep 17 00:00:00 2001 From: Kannan J Date: Fri, 7 Aug 2026 13:08:41 +0000 Subject: [PATCH] Fix ext_proc mock response handling in clientInterceptor_contextPropagatedToStartCall In ExternalProcessorClientInterceptorTest.clientInterceptor_contextPropagatedToStartCall(), the mock ext_proc service blindly returned a ProcessingResponse with setRequestHeaders for every incoming ProcessingRequest. When the downstream RPC finished and sent back response headers, the interceptor sent a ProcessingRequest with responseHeaders. The mock's blind requestHeaders reply caused the interceptor to detect an out-of-order protocol error, triggering internalOnError() which called delayedCall.cancel() on the executor thread. This async cancellation on the executor thread raced with the test code's cleanup proxyCall.cancel() on the test runner thread, causing TSAN to report a data race on the non-volatile field ClientCallImpl.cancelCalled. This commit fixes the test mock to check the request type (hasRequestHeaders() vs. hasResponseHeaders()) before responding, matching the behavior in clientInterceptor_contextPropagatedToListenerCallbacks(). Note: The unsynchronized cancellation between the application thread and an interceptor's cancellation on an executor thread, while technically a data race from TSAN's perspective due to ClientCallImpl.cancelCalled not being volatile, is not consequential in practice because the underlying stream.cancel() and CancellationHandler.tearDown() are thread-safe and idempotent. Therefore, modifying cancelCalled in ClientCallImpl is not necessary. --- .../xds/ExternalProcessorClientInterceptorTest.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/xds/src/test/java/io/grpc/xds/ExternalProcessorClientInterceptorTest.java b/xds/src/test/java/io/grpc/xds/ExternalProcessorClientInterceptorTest.java index 2f7387c1f12..2e8761214a3 100644 --- a/xds/src/test/java/io/grpc/xds/ExternalProcessorClientInterceptorTest.java +++ b/xds/src/test/java/io/grpc/xds/ExternalProcessorClientInterceptorTest.java @@ -14309,9 +14309,15 @@ public StreamObserver process( return new StreamObserver() { @Override public void onNext(ProcessingRequest request) { - responseObserver.onNext(ProcessingResponse.newBuilder() - .setRequestHeaders(HeadersResponse.newBuilder().build()) - .build()); + if (request.hasRequestHeaders()) { + responseObserver.onNext(ProcessingResponse.newBuilder() + .setRequestHeaders(HeadersResponse.newBuilder().build()) + .build()); + } else if (request.hasResponseHeaders()) { + responseObserver.onNext(ProcessingResponse.newBuilder() + .setResponseHeaders(HeadersResponse.newBuilder().build()) + .build()); + } } @Override