all: API refactoring in preparation to support retry stats (#8355)

Rebased PR #8343 into the first commit of this PR, then (the 2nd commit) reverted the part for metric recording of retry attempts. The PR as a whole is mechanical refactoring. No behavior change (except that some of the old code path when tracer is created is moved into the new method `streamCreated()`).

The API change is documented in go/grpc-stats-api-change-for-retry-java
This commit is contained in:
ZHANG Dapeng 2021-07-31 18:33:02 -07:00 committed by GitHub
parent b2764595e6
commit 860e97d12a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 1210 additions and 563 deletions

View File

@ -19,7 +19,6 @@ package io.grpc;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import io.grpc.Grpc;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
/** /**
@ -28,6 +27,18 @@ import javax.annotation.concurrent.ThreadSafe;
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/2861") @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2861")
@ThreadSafe @ThreadSafe
public abstract class ClientStreamTracer extends StreamTracer { public abstract class ClientStreamTracer extends StreamTracer {
/**
* The stream is being created on a ready transport.
*
* @param headers the mutable initial metadata. Modifications to it will be sent to the socket but
* not be seen by client interceptors and the application.
*
* @since 1.40.0
*/
public void streamCreated(@Grpc.TransportAttr Attributes transportAttrs, Metadata headers) {
}
/** /**
* Headers has been sent to the socket. * Headers has been sent to the socket.
*/ */
@ -54,22 +65,6 @@ public abstract class ClientStreamTracer extends StreamTracer {
* Factory class for {@link ClientStreamTracer}. * Factory class for {@link ClientStreamTracer}.
*/ */
public abstract static class Factory { public abstract static class Factory {
/**
* Creates a {@link ClientStreamTracer} for a new client stream.
*
* @param callOptions the effective CallOptions of the call
* @param headers the mutable headers of the stream. It can be safely mutated within this
* method. It should not be saved because it is not safe for read or write after the
* method returns.
*
* @deprecated use {@link
* #newClientStreamTracer(io.grpc.ClientStreamTracer.StreamInfo, io.grpc.Metadata)} instead.
*/
@Deprecated
public ClientStreamTracer newClientStreamTracer(CallOptions callOptions, Metadata headers) {
throw new UnsupportedOperationException("Not implemented");
}
/** /**
* Creates a {@link ClientStreamTracer} for a new client stream. This is called inside the * Creates a {@link ClientStreamTracer} for a new client stream. This is called inside the
* transport when it's creating the stream. * transport when it's creating the stream.
@ -81,12 +76,15 @@ public abstract class ClientStreamTracer extends StreamTracer {
* *
* @since 1.20.0 * @since 1.20.0
*/ */
@SuppressWarnings("deprecation")
public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata headers) { public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata headers) {
return newClientStreamTracer(info.getCallOptions(), headers); throw new UnsupportedOperationException("Not implemented");
} }
} }
/** An abstract class for internal use only. */
@Internal
public abstract static class InternalLimitedInfoFactory extends Factory {}
/** /**
* Information about a stream. * Information about a stream.
* *
@ -99,15 +97,21 @@ public abstract class ClientStreamTracer extends StreamTracer {
public static final class StreamInfo { public static final class StreamInfo {
private final Attributes transportAttrs; private final Attributes transportAttrs;
private final CallOptions callOptions; private final CallOptions callOptions;
private final boolean isTransparentRetry;
StreamInfo(Attributes transportAttrs, CallOptions callOptions) { StreamInfo(Attributes transportAttrs, CallOptions callOptions, boolean isTransparentRetry) {
this.transportAttrs = checkNotNull(transportAttrs, "transportAttrs"); this.transportAttrs = checkNotNull(transportAttrs, "transportAttrs");
this.callOptions = checkNotNull(callOptions, "callOptions"); this.callOptions = checkNotNull(callOptions, "callOptions");
this.isTransparentRetry = isTransparentRetry;
} }
/** /**
* Returns the attributes of the transport that this stream was created on. * Returns the attributes of the transport that this stream was created on.
*
* @deprecated Use {@link ClientStreamTracer#streamCreated(Attributes, Metadata)} to handle
* the transport Attributes instead.
*/ */
@Deprecated
@Grpc.TransportAttr @Grpc.TransportAttr
public Attributes getTransportAttrs() { public Attributes getTransportAttrs() {
return transportAttrs; return transportAttrs;
@ -120,16 +124,25 @@ public abstract class ClientStreamTracer extends StreamTracer {
return callOptions; return callOptions;
} }
/**
* Whether the stream is a transparent retry.
*
* @since 1.40.0
*/
public boolean isTransparentRetry() {
return isTransparentRetry;
}
/** /**
* Converts this StreamInfo into a new Builder. * Converts this StreamInfo into a new Builder.
* *
* @since 1.21.0 * @since 1.21.0
*/ */
public Builder toBuilder() { public Builder toBuilder() {
Builder builder = new Builder(); return new Builder()
builder.setTransportAttrs(transportAttrs); .setCallOptions(callOptions)
builder.setCallOptions(callOptions); .setTransportAttrs(transportAttrs)
return builder; .setIsTransparentRetry(isTransparentRetry);
} }
/** /**
@ -146,6 +159,7 @@ public abstract class ClientStreamTracer extends StreamTracer {
return MoreObjects.toStringHelper(this) return MoreObjects.toStringHelper(this)
.add("transportAttrs", transportAttrs) .add("transportAttrs", transportAttrs)
.add("callOptions", callOptions) .add("callOptions", callOptions)
.add("isTransparentRetry", isTransparentRetry)
.toString(); .toString();
} }
@ -157,6 +171,7 @@ public abstract class ClientStreamTracer extends StreamTracer {
public static final class Builder { public static final class Builder {
private Attributes transportAttrs = Attributes.EMPTY; private Attributes transportAttrs = Attributes.EMPTY;
private CallOptions callOptions = CallOptions.DEFAULT; private CallOptions callOptions = CallOptions.DEFAULT;
private boolean isTransparentRetry;
Builder() { Builder() {
} }
@ -164,9 +179,12 @@ public abstract class ClientStreamTracer extends StreamTracer {
/** /**
* Sets the attributes of the transport that this stream was created on. This field is * Sets the attributes of the transport that this stream was created on. This field is
* optional. * optional.
*
* @deprecated Use {@link ClientStreamTracer#streamCreated(Attributes, Metadata)} to handle
* the transport Attributes instead.
*/ */
@Grpc.TransportAttr @Deprecated
public Builder setTransportAttrs(Attributes transportAttrs) { public Builder setTransportAttrs(@Grpc.TransportAttr Attributes transportAttrs) {
this.transportAttrs = checkNotNull(transportAttrs, "transportAttrs cannot be null"); this.transportAttrs = checkNotNull(transportAttrs, "transportAttrs cannot be null");
return this; return this;
} }
@ -179,11 +197,21 @@ public abstract class ClientStreamTracer extends StreamTracer {
return this; return this;
} }
/**
* Sets whether the stream is a transparent retry.
*
* @since 1.40.0
*/
public Builder setIsTransparentRetry(boolean isTransparentRetry) {
this.isTransparentRetry = isTransparentRetry;
return this;
}
/** /**
* Builds a new StreamInfo. * Builds a new StreamInfo.
*/ */
public StreamInfo build() { public StreamInfo build() {
return new StreamInfo(transportAttrs, callOptions); return new StreamInfo(transportAttrs, callOptions, isTransparentRetry);
} }
} }
} }

View File

@ -30,6 +30,7 @@ import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import io.grpc.ClientStreamTracer.StreamInfo;
import io.grpc.internal.SerializingExecutor; import io.grpc.internal.SerializingExecutor;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -271,7 +272,7 @@ public class CallOptionsTest {
} }
} }
private static class FakeTracerFactory extends ClientStreamTracer.Factory { private static class FakeTracerFactory extends ClientStreamTracer.InternalLimitedInfoFactory {
final String name; final String name;
FakeTracerFactory(String name) { FakeTracerFactory(String name) {
@ -279,8 +280,7 @@ public class CallOptionsTest {
} }
@Override @Override
public ClientStreamTracer newClientStreamTracer( public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata headers) {
ClientStreamTracer.StreamInfo info, Metadata headers) {
return new ClientStreamTracer() {}; return new ClientStreamTracer() {};
} }

View File

@ -32,6 +32,7 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import io.grpc.Attributes; import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer;
import io.grpc.Grpc; import io.grpc.Grpc;
import io.grpc.Internal; import io.grpc.Internal;
import io.grpc.InternalChannelz.SocketStats; import io.grpc.InternalChannelz.SocketStats;
@ -632,28 +633,28 @@ public abstract class BinderTransport
public synchronized ClientStream newStream( public synchronized ClientStream newStream(
final MethodDescriptor<?, ?> method, final MethodDescriptor<?, ?> method,
final Metadata headers, final Metadata headers,
final CallOptions callOptions) { final CallOptions callOptions,
ClientStreamTracer[] tracers) {
if (isShutdown()) { if (isShutdown()) {
return newFailingClientStream(shutdownStatus, callOptions, attributes, headers); return newFailingClientStream(shutdownStatus, attributes, headers, tracers);
} else { } else {
int callId = latestCallId++; int callId = latestCallId++;
if (latestCallId == LAST_CALL_ID) { if (latestCallId == LAST_CALL_ID) {
latestCallId = FIRST_CALL_ID; latestCallId = FIRST_CALL_ID;
} }
StatsTraceContext statsTraceContext =
StatsTraceContext.newClientContext(tracers, attributes, headers);
Inbound.ClientInbound inbound = Inbound.ClientInbound inbound =
new Inbound.ClientInbound( new Inbound.ClientInbound(
this, attributes, callId, GrpcUtil.shouldBeCountedForInUse(callOptions)); this, attributes, callId, GrpcUtil.shouldBeCountedForInUse(callOptions));
if (ongoingCalls.putIfAbsent(callId, inbound) != null) { if (ongoingCalls.putIfAbsent(callId, inbound) != null) {
Status failure = Status.INTERNAL.withDescription("Clashing call IDs"); Status failure = Status.INTERNAL.withDescription("Clashing call IDs");
shutdownInternal(failure, true); shutdownInternal(failure, true);
return newFailingClientStream(failure, callOptions, attributes, headers); return newFailingClientStream(failure, attributes, headers, tracers);
} else { } else {
if (inbound.countsForInUse() && numInUseStreams.getAndIncrement() == 0) { if (inbound.countsForInUse() && numInUseStreams.getAndIncrement() == 0) {
clientTransportListener.transportInUse(true); clientTransportListener.transportInUse(true);
} }
StatsTraceContext statsTraceContext =
StatsTraceContext.newClientContext(callOptions, attributes, headers);
Outbound.ClientOutbound outbound = Outbound.ClientOutbound outbound =
new Outbound.ClientOutbound(this, callId, method, headers, statsTraceContext); new Outbound.ClientOutbound(this, callId, method, headers, statsTraceContext);
if (method.getType().clientSendsOneMessage()) { if (method.getType().clientSendsOneMessage()) {
@ -763,12 +764,12 @@ public abstract class BinderTransport
} }
private static ClientStream newFailingClientStream( private static ClientStream newFailingClientStream(
Status failure, CallOptions callOptions, Attributes attributes, Metadata headers) { Status failure, Attributes attributes, Metadata headers,
ClientStreamTracer[] tracers) {
StatsTraceContext statsTraceContext = StatsTraceContext statsTraceContext =
StatsTraceContext.newClientContext(callOptions, attributes, headers); StatsTraceContext.newClientContext(tracers, attributes, headers);
statsTraceContext.clientOutboundHeaders(); statsTraceContext.clientOutboundHeaders();
statsTraceContext.streamClosed(failure); return new FailingClientStream(failure, tracers);
return new FailingClientStream(failure);
} }
private static InternalLogId buildLogId( private static InternalLogId buildLogId(

View File

@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkState;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.Channel; import io.grpc.Channel;
import io.grpc.ClientCall; import io.grpc.ClientCall;
@ -138,15 +139,6 @@ final class CensusStatsModule {
}); });
} }
/**
* Creates a {@link ClientCallTracer} for a new call.
*/
@VisibleForTesting
ClientCallTracer newClientCallTracer(
TagContext parentCtx, String fullMethodName) {
return new ClientCallTracer(this, parentCtx, fullMethodName);
}
/** /**
* Returns the server tracer factory. * Returns the server tracer factory.
*/ */
@ -231,6 +223,7 @@ final class CensusStatsModule {
} }
private final CensusStatsModule module; private final CensusStatsModule module;
final TagContext parentCtx;
private final TagContext startCtx; private final TagContext startCtx;
volatile long outboundMessageCount; volatile long outboundMessageCount;
@ -240,11 +233,22 @@ final class CensusStatsModule {
volatile long outboundUncompressedSize; volatile long outboundUncompressedSize;
volatile long inboundUncompressedSize; volatile long inboundUncompressedSize;
ClientTracer(CensusStatsModule module, TagContext startCtx) { ClientTracer(CensusStatsModule module, TagContext parentCtx, TagContext startCtx) {
this.module = checkNotNull(module, "module"); this.module = checkNotNull(module, "module");
this.parentCtx = parentCtx;
this.startCtx = checkNotNull(startCtx, "startCtx"); this.startCtx = checkNotNull(startCtx, "startCtx");
} }
@Override
public void streamCreated(Attributes transportAttrs, Metadata headers) {
if (module.propagateTags) {
headers.discardAll(module.statsHeader);
if (!module.tagger.empty().equals(parentCtx)) {
headers.put(module.statsHeader, parentCtx);
}
}
}
@Override @Override
@SuppressWarnings("NonAtomicVolatileUpdate") @SuppressWarnings("NonAtomicVolatileUpdate")
public void outboundWireSize(long bytes) { public void outboundWireSize(long bytes) {
@ -315,12 +319,14 @@ final class CensusStatsModule {
} }
@VisibleForTesting @VisibleForTesting
static final class ClientCallTracer extends ClientStreamTracer.Factory { static final class CallAttemptsTracerFactory extends
ClientStreamTracer.InternalLimitedInfoFactory {
@Nullable @Nullable
private static final AtomicReferenceFieldUpdater<ClientCallTracer, ClientTracer> private static final AtomicReferenceFieldUpdater<CallAttemptsTracerFactory, ClientTracer>
streamTracerUpdater; streamTracerUpdater;
@Nullable private static final AtomicIntegerFieldUpdater<ClientCallTracer> callEndedUpdater; @Nullable
private static final AtomicIntegerFieldUpdater<CallAttemptsTracerFactory> callEndedUpdater;
/** /**
* When using Atomic*FieldUpdater, some Samsung Android 5.0.x devices encounter a bug in their * When using Atomic*FieldUpdater, some Samsung Android 5.0.x devices encounter a bug in their
@ -328,14 +334,14 @@ final class CensusStatsModule {
* (potentially racy) direct updates of the volatile variables. * (potentially racy) direct updates of the volatile variables.
*/ */
static { static {
AtomicReferenceFieldUpdater<ClientCallTracer, ClientTracer> tmpStreamTracerUpdater; AtomicReferenceFieldUpdater<CallAttemptsTracerFactory, ClientTracer> tmpStreamTracerUpdater;
AtomicIntegerFieldUpdater<ClientCallTracer> tmpCallEndedUpdater; AtomicIntegerFieldUpdater<CallAttemptsTracerFactory> tmpCallEndedUpdater;
try { try {
tmpStreamTracerUpdater = tmpStreamTracerUpdater =
AtomicReferenceFieldUpdater.newUpdater( AtomicReferenceFieldUpdater.newUpdater(
ClientCallTracer.class, ClientTracer.class, "streamTracer"); CallAttemptsTracerFactory.class, ClientTracer.class, "streamTracer");
tmpCallEndedUpdater = tmpCallEndedUpdater =
AtomicIntegerFieldUpdater.newUpdater(ClientCallTracer.class, "callEnded"); AtomicIntegerFieldUpdater.newUpdater(CallAttemptsTracerFactory.class, "callEnded");
} catch (Throwable t) { } catch (Throwable t) {
logger.log(Level.SEVERE, "Creating atomic field updaters failed", t); logger.log(Level.SEVERE, "Creating atomic field updaters failed", t);
tmpStreamTracerUpdater = null; tmpStreamTracerUpdater = null;
@ -352,7 +358,8 @@ final class CensusStatsModule {
private final TagContext parentCtx; private final TagContext parentCtx;
private final TagContext startCtx; private final TagContext startCtx;
ClientCallTracer(CensusStatsModule module, TagContext parentCtx, String fullMethodName) { CallAttemptsTracerFactory(
CensusStatsModule module, TagContext parentCtx, String fullMethodName) {
this.module = checkNotNull(module); this.module = checkNotNull(module);
this.parentCtx = checkNotNull(parentCtx); this.parentCtx = checkNotNull(parentCtx);
TagValue methodTag = TagValue.create(fullMethodName); TagValue methodTag = TagValue.create(fullMethodName);
@ -370,7 +377,7 @@ final class CensusStatsModule {
@Override @Override
public ClientStreamTracer newClientStreamTracer( public ClientStreamTracer newClientStreamTracer(
ClientStreamTracer.StreamInfo info, Metadata headers) { ClientStreamTracer.StreamInfo info, Metadata headers) {
ClientTracer tracer = new ClientTracer(module, startCtx); ClientTracer tracer = new ClientTracer(module, parentCtx, startCtx);
// TODO(zhangkun83): Once retry or hedging is implemented, a ClientCall may start more than // TODO(zhangkun83): Once retry or hedging is implemented, a ClientCall may start more than
// one streams. We will need to update this file to support them. // one streams. We will need to update this file to support them.
if (streamTracerUpdater != null) { if (streamTracerUpdater != null) {
@ -383,12 +390,6 @@ final class CensusStatsModule {
"Are you creating multiple streams per call? This class doesn't yet support this case"); "Are you creating multiple streams per call? This class doesn't yet support this case");
streamTracer = tracer; streamTracer = tracer;
} }
if (module.propagateTags) {
headers.discardAll(module.statsHeader);
if (!module.tagger.empty().equals(parentCtx)) {
headers.put(module.statsHeader, parentCtx);
}
}
return tracer; return tracer;
} }
@ -416,7 +417,7 @@ final class CensusStatsModule {
long roundtripNanos = stopwatch.elapsed(TimeUnit.NANOSECONDS); long roundtripNanos = stopwatch.elapsed(TimeUnit.NANOSECONDS);
ClientTracer tracer = streamTracer; ClientTracer tracer = streamTracer;
if (tracer == null) { if (tracer == null) {
tracer = new ClientTracer(module, startCtx); tracer = new ClientTracer(module, parentCtx, startCtx);
} }
MeasureMap measureMap = module.statsRecorder.newMeasureMap() MeasureMap measureMap = module.statsRecorder.newMeasureMap()
// TODO(songya): remove the deprecated measure constants once they are completed removed. // TODO(songya): remove the deprecated measure constants once they are completed removed.
@ -686,8 +687,8 @@ final class CensusStatsModule {
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) { MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
// New RPCs on client-side inherit the tag context from the current Context. // New RPCs on client-side inherit the tag context from the current Context.
TagContext parentCtx = tagger.getCurrentTagContext(); TagContext parentCtx = tagger.getCurrentTagContext();
final ClientCallTracer tracerFactory = final CallAttemptsTracerFactory tracerFactory = new CallAttemptsTracerFactory(
newClientCallTracer(parentCtx, method.getFullMethodName()); CensusStatsModule.this, parentCtx, method.getFullMethodName());
ClientCall<ReqT, RespT> call = ClientCall<ReqT, RespT> call =
next.newCall(method, callOptions.withStreamTracerFactory(tracerFactory)); next.newCall(method, callOptions.withStreamTracerFactory(tracerFactory));
return new SimpleForwardingClientCall<ReqT, RespT>(call) { return new SimpleForwardingClientCall<ReqT, RespT>(call) {

View File

@ -19,6 +19,7 @@ package io.grpc.census;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.Channel; import io.grpc.Channel;
import io.grpc.ClientCall; import io.grpc.ClientCall;
@ -222,7 +223,7 @@ final class CensusTracingModule {
} }
@VisibleForTesting @VisibleForTesting
final class ClientCallTracer extends ClientStreamTracer.Factory { final class ClientCallTracer extends ClientStreamTracer.InternalLimitedInfoFactory {
volatile int callEnded; volatile int callEnded;
private final boolean isSampledToLocalTracing; private final boolean isSampledToLocalTracing;
@ -243,11 +244,7 @@ final class CensusTracingModule {
@Override @Override
public ClientStreamTracer newClientStreamTracer( public ClientStreamTracer newClientStreamTracer(
ClientStreamTracer.StreamInfo info, Metadata headers) { ClientStreamTracer.StreamInfo info, Metadata headers) {
if (span != BlankSpan.INSTANCE) { return new ClientTracer(span, tracingHeader);
headers.discardAll(tracingHeader);
headers.put(tracingHeader, span.getContext());
}
return new ClientTracer(span);
} }
/** /**
@ -273,9 +270,19 @@ final class CensusTracingModule {
private static final class ClientTracer extends ClientStreamTracer { private static final class ClientTracer extends ClientStreamTracer {
private final Span span; private final Span span;
final Metadata.Key<SpanContext> tracingHeader;
ClientTracer(Span span) { ClientTracer(Span span, Metadata.Key<SpanContext> tracingHeader) {
this.span = checkNotNull(span, "span"); this.span = checkNotNull(span, "span");
this.tracingHeader = tracingHeader;
}
@Override
public void streamCreated(Attributes transportAtts, Metadata headers) {
if (span != BlankSpan.INSTANCE) {
headers.discardAll(tracingHeader);
headers.put(tracingHeader, span.getContext());
}
} }
@Override @Override

View File

@ -295,7 +295,7 @@ public class CensusModulesTest {
instanceof CensusTracingModule.ClientCallTracer); instanceof CensusTracingModule.ClientCallTracer);
assertTrue( assertTrue(
capturedCallOptions.get().getStreamTracerFactories().get(1) capturedCallOptions.get().getStreamTracerFactories().get(1)
instanceof CensusStatsModule.ClientCallTracer); instanceof CensusStatsModule.CallAttemptsTracerFactory);
// Make the call // Make the call
Metadata headers = new Metadata(); Metadata headers = new Metadata();
@ -388,11 +388,12 @@ public class CensusModulesTest {
new CensusStatsModule( new CensusStatsModule(
tagger, tagCtxSerializer, statsRecorder, fakeClock.getStopwatchSupplier(), tagger, tagCtxSerializer, statsRecorder, fakeClock.getStopwatchSupplier(),
true, recordStarts, recordFinishes, recordRealTime); true, recordStarts, recordFinishes, recordRealTime);
CensusStatsModule.ClientCallTracer callTracer = CensusStatsModule.CallAttemptsTracerFactory callAttemptsTracerFactory =
localCensusStats.newClientCallTracer( new CensusStatsModule.CallAttemptsTracerFactory(
tagger.empty(), method.getFullMethodName()); localCensusStats, tagger.empty(), method.getFullMethodName());
Metadata headers = new Metadata(); Metadata headers = new Metadata();
ClientStreamTracer tracer = callTracer.newClientStreamTracer(STREAM_INFO, headers); ClientStreamTracer tracer =
callAttemptsTracerFactory.newClientStreamTracer(STREAM_INFO, headers);
if (recordStarts) { if (recordStarts) {
StatsTestUtils.MetricsRecord record = statsRecorder.pollRecord(); StatsTestUtils.MetricsRecord record = statsRecorder.pollRecord();
@ -455,7 +456,7 @@ public class CensusModulesTest {
tracer.inboundUncompressedSize(552); tracer.inboundUncompressedSize(552);
tracer.streamClosed(Status.OK); tracer.streamClosed(Status.OK);
callTracer.callEnded(Status.OK); callAttemptsTracerFactory.callEnded(Status.OK);
if (recordFinishes) { if (recordFinishes) {
StatsTestUtils.MetricsRecord record = statsRecorder.pollRecord(); StatsTestUtils.MetricsRecord record = statsRecorder.pollRecord();
@ -522,6 +523,7 @@ public class CensusModulesTest {
censusTracing.newClientCallTracer(null, method); censusTracing.newClientCallTracer(null, method);
Metadata headers = new Metadata(); Metadata headers = new Metadata();
ClientStreamTracer clientStreamTracer = callTracer.newClientStreamTracer(STREAM_INFO, headers); ClientStreamTracer clientStreamTracer = callTracer.newClientStreamTracer(STREAM_INFO, headers);
clientStreamTracer.streamCreated(Attributes.EMPTY, headers);
verify(tracer).spanBuilderWithExplicitParent( verify(tracer).spanBuilderWithExplicitParent(
eq("Sent.package1.service2.method3"), ArgumentMatchers.<Span>isNull()); eq("Sent.package1.service2.method3"), ArgumentMatchers.<Span>isNull());
verify(spyClientSpan, never()).end(any(EndSpanOptions.class)); verify(spyClientSpan, never()).end(any(EndSpanOptions.class));
@ -575,11 +577,15 @@ public class CensusModulesTest {
@Test @Test
public void clientStreamNeverCreatedStillRecordStats() { public void clientStreamNeverCreatedStillRecordStats() {
CensusStatsModule.ClientCallTracer callTracer = CensusStatsModule.CallAttemptsTracerFactory callAttemptsTracerFactory =
censusStats.newClientCallTracer(tagger.empty(), method.getFullMethodName()); new CensusStatsModule.CallAttemptsTracerFactory(
censusStats, tagger.empty(), method.getFullMethodName());
ClientStreamTracer streamTracer =
callAttemptsTracerFactory.newClientStreamTracer(STREAM_INFO, new Metadata());
fakeClock.forwardTime(3000, MILLISECONDS); fakeClock.forwardTime(3000, MILLISECONDS);
callTracer.callEnded(Status.DEADLINE_EXCEEDED.withDescription("3 seconds")); Status status = Status.DEADLINE_EXCEEDED.withDescription("3 seconds");
streamTracer.streamClosed(status);
callAttemptsTracerFactory.callEnded(status);
// Upstart record // Upstart record
StatsTestUtils.MetricsRecord record = statsRecorder.pollRecord(); StatsTestUtils.MetricsRecord record = statsRecorder.pollRecord();
@ -680,10 +686,13 @@ public class CensusModulesTest {
fakeClock.getStopwatchSupplier(), fakeClock.getStopwatchSupplier(),
propagate, recordStats, recordStats, recordStats); propagate, recordStats, recordStats, recordStats);
Metadata headers = new Metadata(); Metadata headers = new Metadata();
CensusStatsModule.ClientCallTracer callTracer = CensusStatsModule.CallAttemptsTracerFactory callAttemptsTracerFactory =
census.newClientCallTracer(clientCtx, method.getFullMethodName()); new CensusStatsModule.CallAttemptsTracerFactory(
census, clientCtx, method.getFullMethodName());
// This propagates clientCtx to headers if propagates==true // This propagates clientCtx to headers if propagates==true
callTracer.newClientStreamTracer(STREAM_INFO, headers); ClientStreamTracer streamTracer =
callAttemptsTracerFactory.newClientStreamTracer(STREAM_INFO, headers);
streamTracer.streamCreated(Attributes.EMPTY, headers);
if (recordStats) { if (recordStats) {
// Client upstart record // Client upstart record
StatsTestUtils.MetricsRecord clientRecord = statsRecorder.pollRecord(); StatsTestUtils.MetricsRecord clientRecord = statsRecorder.pollRecord();
@ -746,7 +755,8 @@ public class CensusModulesTest {
// Verifies that the client tracer factory uses clientCtx, which includes the custom tags, to // Verifies that the client tracer factory uses clientCtx, which includes the custom tags, to
// record stats. // record stats.
callTracer.callEnded(Status.OK); streamTracer.streamClosed(Status.OK);
callAttemptsTracerFactory.callEnded(Status.OK);
if (recordStats) { if (recordStats) {
// Client completion record // Client completion record
@ -769,10 +779,12 @@ public class CensusModulesTest {
@Test @Test
public void statsHeadersNotPropagateDefaultContext() { public void statsHeadersNotPropagateDefaultContext() {
CensusStatsModule.ClientCallTracer callTracer = CensusStatsModule.CallAttemptsTracerFactory callAttemptsTracerFactory =
censusStats.newClientCallTracer(tagger.empty(), method.getFullMethodName()); new CensusStatsModule.CallAttemptsTracerFactory(
censusStats, tagger.empty(), method.getFullMethodName());
Metadata headers = new Metadata(); Metadata headers = new Metadata();
callTracer.newClientStreamTracer(STREAM_INFO, headers); callAttemptsTracerFactory.newClientStreamTracer(STREAM_INFO, headers)
.streamCreated(Attributes.EMPTY, headers);
assertFalse(headers.containsKey(censusStats.statsHeader)); assertFalse(headers.containsKey(censusStats.statsHeader));
// Clear recorded stats to satisfy the assertions in wrapUp() // Clear recorded stats to satisfy the assertions in wrapUp()
statsRecorder.rolloverRecords(); statsRecorder.rolloverRecords();
@ -803,7 +815,8 @@ public class CensusModulesTest {
CensusTracingModule.ClientCallTracer callTracer = CensusTracingModule.ClientCallTracer callTracer =
censusTracing.newClientCallTracer(fakeClientParentSpan, method); censusTracing.newClientCallTracer(fakeClientParentSpan, method);
Metadata headers = new Metadata(); Metadata headers = new Metadata();
callTracer.newClientStreamTracer(STREAM_INFO, headers); ClientStreamTracer streamTracer = callTracer.newClientStreamTracer(STREAM_INFO, headers);
streamTracer.streamCreated(Attributes.EMPTY, headers);
verify(mockTracingPropagationHandler).toByteArray(same(fakeClientSpanContext)); verify(mockTracingPropagationHandler).toByteArray(same(fakeClientSpanContext));
verifyNoMoreInteractions(mockTracingPropagationHandler); verifyNoMoreInteractions(mockTracingPropagationHandler);
@ -831,7 +844,8 @@ public class CensusModulesTest {
censusTracing.newClientCallTracer(fakeClientParentSpan, method); censusTracing.newClientCallTracer(fakeClientParentSpan, method);
Metadata headers = new Metadata(); Metadata headers = new Metadata();
callTracer.newClientStreamTracer(STREAM_INFO, headers); ClientStreamTracer streamTracer = callTracer.newClientStreamTracer(STREAM_INFO, headers);
streamTracer.streamCreated(Attributes.EMPTY, headers);
assertThat(headers.keys()).isNotEmpty(); assertThat(headers.keys()).isNotEmpty();
} }
@ -845,7 +859,7 @@ public class CensusModulesTest {
CensusTracingModule.ClientCallTracer callTracer = CensusTracingModule.ClientCallTracer callTracer =
censusTracing.newClientCallTracer(BlankSpan.INSTANCE, method); censusTracing.newClientCallTracer(BlankSpan.INSTANCE, method);
callTracer.newClientStreamTracer(STREAM_INFO, headers); callTracer.newClientStreamTracer(STREAM_INFO, headers).streamCreated(Attributes.EMPTY, headers);
assertThat(headers.keys()).isEmpty(); assertThat(headers.keys()).isEmpty();
} }
@ -862,7 +876,7 @@ public class CensusModulesTest {
CensusTracingModule.ClientCallTracer callTracer = CensusTracingModule.ClientCallTracer callTracer =
censusTracing.newClientCallTracer(BlankSpan.INSTANCE, method); censusTracing.newClientCallTracer(BlankSpan.INSTANCE, method);
callTracer.newClientStreamTracer(STREAM_INFO, headers); callTracer.newClientStreamTracer(STREAM_INFO, headers).streamCreated(Attributes.EMPTY, headers);
assertThat(headers.keys()).containsExactlyElementsIn(originalHeaderKeys); assertThat(headers.keys()).containsExactlyElementsIn(originalHeaderKeys);
} }
@ -1186,13 +1200,18 @@ public class CensusModulesTest {
tagger, tagCtxSerializer, localStats.getStatsRecorder(), fakeClock.getStopwatchSupplier(), tagger, tagCtxSerializer, localStats.getStatsRecorder(), fakeClock.getStopwatchSupplier(),
false, false, true, false /* real-time */); false, false, true, false /* real-time */);
CensusStatsModule.ClientCallTracer callTracer = CensusStatsModule.CallAttemptsTracerFactory callAttemptsTracerFactory =
localCensusStats.newClientCallTracer( new CensusStatsModule.CallAttemptsTracerFactory(
tagger.empty(), method.getFullMethodName()); localCensusStats, tagger.empty(), method.getFullMethodName());
callTracer.newClientStreamTracer(STREAM_INFO, new Metadata()); Metadata headers = new Metadata();
ClientStreamTracer tracer =
callAttemptsTracerFactory.newClientStreamTracer(STREAM_INFO, headers);
tracer.streamCreated(Attributes.EMPTY, headers);
fakeClock.forwardTime(30, MILLISECONDS); fakeClock.forwardTime(30, MILLISECONDS);
callTracer.callEnded(Status.PERMISSION_DENIED.withDescription("No you don't")); Status status = Status.PERMISSION_DENIED.withDescription("No you don't");
tracer.streamClosed(status);
callAttemptsTracerFactory.callEnded(status);
// Give OpenCensus a chance to update the views asynchronously. // Give OpenCensus a chance to update the views asynchronously.
Thread.sleep(100); Thread.sleep(100);

View File

@ -17,7 +17,7 @@
package io.grpc.internal; package io.grpc.internal;
import io.grpc.Attributes; import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.ClientStreamTracer;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.MethodDescriptor; import io.grpc.MethodDescriptor;
import io.grpc.ServerStreamTracer; import io.grpc.ServerStreamTracer;
@ -50,7 +50,8 @@ public class StatsTraceContextBenchmark {
@BenchmarkMode(Mode.SampleTime) @BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS) @OutputTimeUnit(TimeUnit.NANOSECONDS)
public StatsTraceContext newClientContext() { public StatsTraceContext newClientContext() {
return StatsTraceContext.newClientContext(CallOptions.DEFAULT, Attributes.EMPTY, emptyMetadata); return StatsTraceContext.newClientContext(
new ClientStreamTracer[] { new ClientStreamTracer() {} }, Attributes.EMPTY, emptyMetadata);
} }
/** /**

View File

@ -26,6 +26,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
import io.grpc.Attributes; import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer;
import io.grpc.Compressor; import io.grpc.Compressor;
import io.grpc.Deadline; import io.grpc.Deadline;
import io.grpc.Decompressor; import io.grpc.Decompressor;
@ -205,10 +206,12 @@ final class InProcessTransport implements ServerTransport, ConnectionClientTrans
@Override @Override
public synchronized ClientStream newStream( public synchronized ClientStream newStream(
final MethodDescriptor<?, ?> method, final Metadata headers, final CallOptions callOptions) { MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions,
ClientStreamTracer[] tracers) {
StatsTraceContext statsTraceContext =
StatsTraceContext.newClientContext(tracers, getAttributes(), headers);
if (shutdownStatus != null) { if (shutdownStatus != null) {
return failedClientStream( return failedClientStream(statsTraceContext, shutdownStatus);
StatsTraceContext.newClientContext(callOptions, attributes, headers), shutdownStatus);
} }
headers.put(GrpcUtil.USER_AGENT_KEY, userAgent); headers.put(GrpcUtil.USER_AGENT_KEY, userAgent);
@ -226,12 +229,12 @@ final class InProcessTransport implements ServerTransport, ConnectionClientTrans
"Request metadata larger than %d: %d", "Request metadata larger than %d: %d",
serverMaxInboundMetadataSize, serverMaxInboundMetadataSize,
metadataSize)); metadataSize));
return failedClientStream( return failedClientStream(statsTraceContext, status);
StatsTraceContext.newClientContext(callOptions, attributes, headers), status);
} }
} }
return new InProcessStream(method, headers, callOptions, authority).clientStream; return new InProcessStream(method, headers, callOptions, authority, statsTraceContext)
.clientStream;
} }
private ClientStream failedClientStream( private ClientStream failedClientStream(
@ -377,12 +380,12 @@ final class InProcessTransport implements ServerTransport, ConnectionClientTrans
private InProcessStream( private InProcessStream(
MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions, MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions,
String authority) { String authority , StatsTraceContext statsTraceContext) {
this.method = checkNotNull(method, "method"); this.method = checkNotNull(method, "method");
this.headers = checkNotNull(headers, "headers"); this.headers = checkNotNull(headers, "headers");
this.callOptions = checkNotNull(callOptions, "callOptions"); this.callOptions = checkNotNull(callOptions, "callOptions");
this.authority = authority; this.authority = authority;
this.clientStream = new InProcessClientStream(callOptions, headers); this.clientStream = new InProcessClientStream(callOptions, statsTraceContext);
this.serverStream = new InProcessServerStream(method, headers); this.serverStream = new InProcessServerStream(method, headers);
} }
@ -673,9 +676,10 @@ final class InProcessTransport implements ServerTransport, ConnectionClientTrans
@GuardedBy("this") @GuardedBy("this")
private int outboundSeqNo; private int outboundSeqNo;
InProcessClientStream(CallOptions callOptions, Metadata headers) { InProcessClientStream(
CallOptions callOptions, StatsTraceContext statsTraceContext) {
this.callOptions = callOptions; this.callOptions = callOptions;
statsTraceCtx = StatsTraceContext.newClientContext(callOptions, attributes, headers); statsTraceCtx = statsTraceContext;
} }
private synchronized void setListener(ServerStreamListener listener) { private synchronized void setListener(ServerStreamListener listener) {

View File

@ -25,6 +25,7 @@ import io.grpc.CallCredentials.RequestInfo;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ChannelCredentials; import io.grpc.ChannelCredentials;
import io.grpc.ChannelLogger; import io.grpc.ChannelLogger;
import io.grpc.ClientStreamTracer;
import io.grpc.CompositeCallCredentials; import io.grpc.CompositeCallCredentials;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.MethodDescriptor; import io.grpc.MethodDescriptor;
@ -104,7 +105,8 @@ final class CallCredentialsApplyingTransportFactory implements ClientTransportFa
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public ClientStream newStream( public ClientStream newStream(
final MethodDescriptor<?, ?> method, Metadata headers, final CallOptions callOptions) { final MethodDescriptor<?, ?> method, Metadata headers, final CallOptions callOptions,
ClientStreamTracer[] tracers) {
CallCredentials creds = callOptions.getCredentials(); CallCredentials creds = callOptions.getCredentials();
if (creds == null) { if (creds == null) {
creds = channelCallCredentials; creds = channelCallCredentials;
@ -113,10 +115,10 @@ final class CallCredentialsApplyingTransportFactory implements ClientTransportFa
} }
if (creds != null) { if (creds != null) {
MetadataApplierImpl applier = new MetadataApplierImpl( MetadataApplierImpl applier = new MetadataApplierImpl(
delegate, method, headers, callOptions, applierListener); delegate, method, headers, callOptions, applierListener, tracers);
if (pendingApplier.incrementAndGet() > 0) { if (pendingApplier.incrementAndGet() > 0) {
applierListener.onComplete(); applierListener.onComplete();
return new FailingClientStream(shutdownStatus); return new FailingClientStream(shutdownStatus, tracers);
} }
RequestInfo requestInfo = new RequestInfo() { RequestInfo requestInfo = new RequestInfo() {
@Override @Override
@ -152,9 +154,9 @@ final class CallCredentialsApplyingTransportFactory implements ClientTransportFa
return applier.returnStream(); return applier.returnStream();
} else { } else {
if (pendingApplier.get() >= 0) { if (pendingApplier.get() >= 0) {
return new FailingClientStream(shutdownStatus); return new FailingClientStream(shutdownStatus, tracers);
} }
return delegate.newStream(method, headers, callOptions); return delegate.newStream(method, headers, callOptions, tracers);
} }
} }

View File

@ -33,6 +33,7 @@ import com.google.common.base.MoreObjects;
import io.grpc.Attributes; import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientCall; import io.grpc.ClientCall;
import io.grpc.ClientStreamTracer;
import io.grpc.Codec; import io.grpc.Codec;
import io.grpc.Compressor; import io.grpc.Compressor;
import io.grpc.CompressorRegistry; import io.grpc.CompressorRegistry;
@ -254,9 +255,11 @@ final class ClientCallImpl<ReqT, RespT> extends ClientCall<ReqT, RespT> {
effectiveDeadline, context.getDeadline(), callOptions.getDeadline()); effectiveDeadline, context.getDeadline(), callOptions.getDeadline());
stream = clientStreamProvider.newStream(method, callOptions, headers, context); stream = clientStreamProvider.newStream(method, callOptions, headers, context);
} else { } else {
ClientStreamTracer[] tracers = GrpcUtil.getClientStreamTracers(callOptions, headers, false);
stream = new FailingClientStream( stream = new FailingClientStream(
DEADLINE_EXCEEDED.withDescription( DEADLINE_EXCEEDED.withDescription(
"ClientCall started after deadline exceeded: " + effectiveDeadline)); "ClientCall started after deadline exceeded: " + effectiveDeadline),
tracers);
} }
if (callExecutorIsDirect) { if (callExecutorIsDirect) {

View File

@ -17,6 +17,7 @@
package io.grpc.internal; package io.grpc.internal;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer;
import io.grpc.InternalChannelz.SocketStats; import io.grpc.InternalChannelz.SocketStats;
import io.grpc.InternalInstrumented; import io.grpc.InternalInstrumented;
import io.grpc.Metadata; import io.grpc.Metadata;
@ -46,10 +47,15 @@ public interface ClientTransport extends InternalInstrumented<SocketStats> {
* @param method the descriptor of the remote method to be called for this stream. * @param method the descriptor of the remote method to be called for this stream.
* @param headers to send at the beginning of the call * @param headers to send at the beginning of the call
* @param callOptions runtime options of the call * @param callOptions runtime options of the call
* @param tracers a non-empty array of tracers. The last element in it is reserved to be set by
* the load balancer's pick result and otherwise is a no-op tracer.
* @return the newly created stream. * @return the newly created stream.
*/ */
// TODO(nmittler): Consider also throwing for stopping. // TODO(nmittler): Consider also throwing for stopping.
ClientStream newStream(MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions); ClientStream newStream(
MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions,
// Using array for tracers instead of a list or composition for better performance.
ClientStreamTracer[] tracers);
/** /**
* Pings a remote endpoint. When an acknowledgement is received, the given callback will be * Pings a remote endpoint. When an acknowledgement is received, the given callback will be

View File

@ -20,6 +20,7 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer;
import io.grpc.Context; import io.grpc.Context;
import io.grpc.InternalChannelz.SocketStats; import io.grpc.InternalChannelz.SocketStats;
import io.grpc.InternalLogId; import io.grpc.InternalLogId;
@ -133,7 +134,8 @@ final class DelayedClientTransport implements ManagedClientTransport {
*/ */
@Override @Override
public final ClientStream newStream( public final ClientStream newStream(
MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions) { MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions,
ClientStreamTracer[] tracers) {
try { try {
PickSubchannelArgs args = new PickSubchannelArgsImpl(method, headers, callOptions); PickSubchannelArgs args = new PickSubchannelArgsImpl(method, headers, callOptions);
SubchannelPicker picker = null; SubchannelPicker picker = null;
@ -141,14 +143,14 @@ final class DelayedClientTransport implements ManagedClientTransport {
while (true) { while (true) {
synchronized (lock) { synchronized (lock) {
if (shutdownStatus != null) { if (shutdownStatus != null) {
return new FailingClientStream(shutdownStatus); return new FailingClientStream(shutdownStatus, tracers);
} }
if (lastPicker == null) { if (lastPicker == null) {
return createPendingStream(args); return createPendingStream(args, tracers);
} }
// Check for second time through the loop, and whether anything changed // Check for second time through the loop, and whether anything changed
if (picker != null && pickerVersion == lastPickerVersion) { if (picker != null && pickerVersion == lastPickerVersion) {
return createPendingStream(args); return createPendingStream(args, tracers);
} }
picker = lastPicker; picker = lastPicker;
pickerVersion = lastPickerVersion; pickerVersion = lastPickerVersion;
@ -158,7 +160,8 @@ final class DelayedClientTransport implements ManagedClientTransport {
callOptions.isWaitForReady()); callOptions.isWaitForReady());
if (transport != null) { if (transport != null) {
return transport.newStream( return transport.newStream(
args.getMethodDescriptor(), args.getHeaders(), args.getCallOptions()); args.getMethodDescriptor(), args.getHeaders(), args.getCallOptions(),
tracers);
} }
// This picker's conclusion is "buffer". If there hasn't been a newer picker set (possible // This picker's conclusion is "buffer". If there hasn't been a newer picker set (possible
// race with reprocess()), we will buffer it. Otherwise, will try with the new picker. // race with reprocess()), we will buffer it. Otherwise, will try with the new picker.
@ -173,8 +176,9 @@ final class DelayedClientTransport implements ManagedClientTransport {
* schedule tasks on syncContext. * schedule tasks on syncContext.
*/ */
@GuardedBy("lock") @GuardedBy("lock")
private PendingStream createPendingStream(PickSubchannelArgs args) { private PendingStream createPendingStream(
PendingStream pendingStream = new PendingStream(args); PickSubchannelArgs args, ClientStreamTracer[] tracers) {
PendingStream pendingStream = new PendingStream(args, tracers);
pendingStreams.add(pendingStream); pendingStreams.add(pendingStream);
if (getPendingStreamsCount() == 1) { if (getPendingStreamsCount() == 1) {
syncContext.executeLater(reportTransportInUse); syncContext.executeLater(reportTransportInUse);
@ -239,7 +243,8 @@ final class DelayedClientTransport implements ManagedClientTransport {
} }
if (savedReportTransportTerminated != null) { if (savedReportTransportTerminated != null) {
for (PendingStream stream : savedPendingStreams) { for (PendingStream stream : savedPendingStreams) {
Runnable runnable = stream.setStream(new FailingClientStream(status, RpcProgress.REFUSED)); Runnable runnable = stream.setStream(
new FailingClientStream(status, RpcProgress.REFUSED, stream.tracers));
if (runnable != null) { if (runnable != null) {
// Drain in-line instead of using an executor as failing stream just throws everything // Drain in-line instead of using an executor as failing stream just throws everything
// away. This is essentially the same behavior as DelayedStream.cancel() but can be done // away. This is essentially the same behavior as DelayedStream.cancel() but can be done
@ -346,9 +351,11 @@ final class DelayedClientTransport implements ManagedClientTransport {
private class PendingStream extends DelayedStream { private class PendingStream extends DelayedStream {
private final PickSubchannelArgs args; private final PickSubchannelArgs args;
private final Context context = Context.current(); private final Context context = Context.current();
private final ClientStreamTracer[] tracers;
private PendingStream(PickSubchannelArgs args) { private PendingStream(PickSubchannelArgs args, ClientStreamTracer[] tracers) {
this.args = args; this.args = args;
this.tracers = tracers;
} }
/** Runnable may be null. */ /** Runnable may be null. */
@ -357,7 +364,8 @@ final class DelayedClientTransport implements ManagedClientTransport {
Context origContext = context.attach(); Context origContext = context.attach();
try { try {
realStream = transport.newStream( realStream = transport.newStream(
args.getMethodDescriptor(), args.getHeaders(), args.getCallOptions()); args.getMethodDescriptor(), args.getHeaders(), args.getCallOptions(),
tracers);
} finally { } finally {
context.detach(origContext); context.detach(origContext);
} }
@ -382,6 +390,13 @@ final class DelayedClientTransport implements ManagedClientTransport {
syncContext.drain(); syncContext.drain();
} }
@Override
protected void onEarlyCancellation(Status reason) {
for (ClientStreamTracer tracer : tracers) {
tracer.streamClosed(reason);
}
}
@Override @Override
public void appendTimeoutInsight(InsightBuilder insight) { public void appendTimeoutInsight(InsightBuilder insight) {
if (args.getCallOptions().isWaitForReady()) { if (args.getCallOptions().isWaitForReady()) {

View File

@ -324,11 +324,15 @@ class DelayedStream implements ClientStream {
}); });
} else { } else {
drainPendingCalls(); drainPendingCalls();
onEarlyCancellation(reason);
// Note that listener is a DelayedStreamListener // Note that listener is a DelayedStreamListener
listener.closed(reason, RpcProgress.PROCESSED, new Metadata()); listener.closed(reason, RpcProgress.PROCESSED, new Metadata());
} }
} }
protected void onEarlyCancellation(Status reason) {
}
@GuardedBy("this") @GuardedBy("this")
private void setRealStream(ClientStream realStream) { private void setRealStream(ClientStream realStream) {
checkState(this.realStream == null, "realStream already set to %s", this.realStream); checkState(this.realStream == null, "realStream already set to %s", this.realStream);

View File

@ -18,6 +18,7 @@ package io.grpc.internal;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import io.grpc.ClientStreamTracer;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.Status; import io.grpc.Status;
import io.grpc.internal.ClientStreamListener.RpcProgress; import io.grpc.internal.ClientStreamListener.RpcProgress;
@ -30,27 +31,33 @@ public final class FailingClientStream extends NoopClientStream {
private boolean started; private boolean started;
private final Status error; private final Status error;
private final RpcProgress rpcProgress; private final RpcProgress rpcProgress;
private final ClientStreamTracer[] tracers;
/** /**
* Creates a {@code FailingClientStream} that would fail with the given error. * Creates a {@code FailingClientStream} that would fail with the given error.
*/ */
public FailingClientStream(Status error) { public FailingClientStream(Status error, ClientStreamTracer[] tracers) {
this(error, RpcProgress.PROCESSED); this(error, RpcProgress.PROCESSED, tracers);
} }
/** /**
* Creates a {@code FailingClientStream} that would fail with the given error. * Creates a {@code FailingClientStream} that would fail with the given error.
*/ */
public FailingClientStream(Status error, RpcProgress rpcProgress) { public FailingClientStream(
Status error, RpcProgress rpcProgress, ClientStreamTracer[] tracers) {
Preconditions.checkArgument(!error.isOk(), "error must not be OK"); Preconditions.checkArgument(!error.isOk(), "error must not be OK");
this.error = error; this.error = error;
this.rpcProgress = rpcProgress; this.rpcProgress = rpcProgress;
this.tracers = tracers;
} }
@Override @Override
public void start(ClientStreamListener listener) { public void start(ClientStreamListener listener) {
Preconditions.checkState(!started, "already started"); Preconditions.checkState(!started, "already started");
started = true; started = true;
for (ClientStreamTracer tracer : tracers) {
tracer.streamClosed(error);
}
listener.closed(error, rpcProgress, new Metadata()); listener.closed(error, rpcProgress, new Metadata());
} }

View File

@ -21,6 +21,7 @@ import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer;
import io.grpc.InternalChannelz.SocketStats; import io.grpc.InternalChannelz.SocketStats;
import io.grpc.InternalLogId; import io.grpc.InternalLogId;
import io.grpc.Metadata; import io.grpc.Metadata;
@ -45,8 +46,9 @@ class FailingClientTransport implements ClientTransport {
@Override @Override
public ClientStream newStream( public ClientStream newStream(
MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions) { MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions,
return new FailingClientStream(error, rpcProgress); ClientStreamTracer[] tracers) {
return new FailingClientStream(error, rpcProgress, tracers);
} }
@Override @Override

View File

@ -0,0 +1,101 @@
/*
* Copyright 2021 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.grpc.internal;
import com.google.common.base.MoreObjects;
import io.grpc.Attributes;
import io.grpc.ClientStreamTracer;
import io.grpc.Metadata;
import io.grpc.Status;
public abstract class ForwardingClientStreamTracer extends ClientStreamTracer {
/**
* Returns the underlying {@code ClientStreamTracer}.
*/
protected abstract ClientStreamTracer delegate();
@Override
public void streamCreated(Attributes transportAttrs, Metadata headers) {
delegate().streamCreated(transportAttrs, headers);
}
@Override
public void outboundHeaders() {
delegate().outboundHeaders();
}
@Override
public void inboundHeaders() {
delegate().inboundHeaders();
}
@Override
public void inboundTrailers(Metadata trailers) {
delegate().inboundTrailers(trailers);
}
@Override
public void streamClosed(Status status) {
delegate().streamClosed(status);
}
@Override
public void outboundMessage(int seqNo) {
delegate().outboundMessage(seqNo);
}
@Override
public void inboundMessage(int seqNo) {
delegate().inboundMessage(seqNo);
}
@Override
public void outboundMessageSent(int seqNo, long optionalWireSize, long optionalUncompressedSize) {
delegate().outboundMessageSent(seqNo, optionalWireSize, optionalUncompressedSize);
}
@Override
public void inboundMessageRead(int seqNo, long optionalWireSize, long optionalUncompressedSize) {
delegate().inboundMessageRead(seqNo, optionalWireSize, optionalUncompressedSize);
}
@Override
public void outboundWireSize(long bytes) {
delegate().outboundWireSize(bytes);
}
@Override
public void outboundUncompressedSize(long bytes) {
delegate().outboundUncompressedSize(bytes);
}
@Override
public void inboundWireSize(long bytes) {
delegate().inboundWireSize(bytes);
}
@Override
public void inboundUncompressedSize(long bytes) {
delegate().inboundUncompressedSize(bytes);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("delegate", delegate()).toString();
}
}

View File

@ -20,6 +20,7 @@ import com.google.common.base.MoreObjects;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import io.grpc.Attributes; import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer;
import io.grpc.InternalChannelz.SocketStats; import io.grpc.InternalChannelz.SocketStats;
import io.grpc.InternalLogId; import io.grpc.InternalLogId;
import io.grpc.Metadata; import io.grpc.Metadata;
@ -45,8 +46,9 @@ abstract class ForwardingConnectionClientTransport implements ConnectionClientTr
@Override @Override
public ClientStream newStream( public ClientStream newStream(
MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions) { MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions,
return delegate().newStream(method, headers, callOptions); ClientStreamTracer[] tracers) {
return delegate().newStream(method, headers, callOptions, tracers);
} }
@Override @Override

View File

@ -17,6 +17,7 @@
package io.grpc.internal; package io.grpc.internal;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Objects; import com.google.common.base.Objects;
@ -26,8 +27,11 @@ import com.google.common.base.Stopwatch;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder;
import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer; import io.grpc.ClientStreamTracer;
import io.grpc.ClientStreamTracer.InternalLimitedInfoFactory;
import io.grpc.ClientStreamTracer.StreamInfo;
import io.grpc.InternalChannelz.SocketStats; import io.grpc.InternalChannelz.SocketStats;
import io.grpc.InternalLogId; import io.grpc.InternalLogId;
import io.grpc.InternalMetadata; import io.grpc.InternalMetadata;
@ -54,12 +58,14 @@ import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -253,6 +259,8 @@ public final class GrpcUtil {
public static final CallOptions.Key<Boolean> CALL_OPTIONS_RPC_OWNED_BY_BALANCER = public static final CallOptions.Key<Boolean> CALL_OPTIONS_RPC_OWNED_BY_BALANCER =
CallOptions.Key.create("io.grpc.internal.CALL_OPTIONS_RPC_OWNED_BY_BALANCER"); CallOptions.Key.create("io.grpc.internal.CALL_OPTIONS_RPC_OWNED_BY_BALANCER");
private static final ClientStreamTracer NOOP_TRACER = new ClientStreamTracer() {};
/** /**
* Returns true if an RPC with the given properties should be counted when calculating the * Returns true if an RPC with the given properties should be counted when calculating the
* in-use state of a transport. * in-use state of a transport.
@ -711,9 +719,14 @@ public final class GrpcUtil {
return new ClientTransport() { return new ClientTransport() {
@Override @Override
public ClientStream newStream( public ClientStream newStream(
MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions) { MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions,
return transport.newStream( ClientStreamTracer[] tracers) {
method, headers, callOptions.withStreamTracerFactory(streamTracerFactory)); StreamInfo info = StreamInfo.newBuilder().setCallOptions(callOptions).build();
ClientStreamTracer streamTracer =
newClientStreamTracer(streamTracerFactory, info, headers);
checkState(tracers[tracers.length - 1] == NOOP_TRACER, "lb tracer already assigned");
tracers[tracers.length - 1] = streamTracer;
return transport.newStream(method, headers, callOptions, tracers);
} }
@Override @Override
@ -743,6 +756,64 @@ public final class GrpcUtil {
return null; return null;
} }
/** Gets stream tracers based on CallOptions. */
public static ClientStreamTracer[] getClientStreamTracers(
CallOptions callOptions, Metadata headers, boolean isTransparentRetry) {
List<ClientStreamTracer.Factory> factories = callOptions.getStreamTracerFactories();
ClientStreamTracer[] tracers = new ClientStreamTracer[factories.size() + 1];
StreamInfo streamInfo = StreamInfo.newBuilder()
.setCallOptions(callOptions)
.setIsTransparentRetry(isTransparentRetry)
.build();
for (int i = 0; i < factories.size(); i++) {
tracers[i] = newClientStreamTracer(factories.get(i), streamInfo, headers);
}
// Reserved to be set later by the lb as per the API contract of ClientTransport.newStream().
// See also GrpcUtil.getTransportFromPickResult()
tracers[tracers.length - 1] = NOOP_TRACER;
return tracers;
}
// A util function for backward compatibility to support deprecated StreamInfo.getAttributes().
@VisibleForTesting
static ClientStreamTracer newClientStreamTracer(
final ClientStreamTracer.Factory streamTracerFactory, final StreamInfo info,
final Metadata headers) {
ClientStreamTracer streamTracer;
if (streamTracerFactory instanceof InternalLimitedInfoFactory) {
streamTracer = streamTracerFactory.newClientStreamTracer(info, headers);
} else {
streamTracer = new ForwardingClientStreamTracer() {
final ClientStreamTracer noop = new ClientStreamTracer() {};
AtomicReference<ClientStreamTracer> delegate = new AtomicReference<>(noop);
void maybeInit(StreamInfo info, Metadata headers) {
delegate.compareAndSet(noop, streamTracerFactory.newClientStreamTracer(info, headers));
}
@Override
protected ClientStreamTracer delegate() {
return delegate.get();
}
@SuppressWarnings("deprecation")
@Override
public void streamCreated(Attributes transportAttrs, Metadata headers) {
StreamInfo streamInfo = info.toBuilder().setTransportAttrs(transportAttrs).build();
maybeInit(streamInfo, headers);
delegate().streamCreated(transportAttrs, headers);
}
@Override
public void streamClosed(Status status) {
maybeInit(info, headers);
delegate().streamClosed(status);
}
};
}
return streamTracer;
}
/** Quietly closes all messages in MessageProducer. */ /** Quietly closes all messages in MessageProducer. */
static void closeQuietly(MessageProducer producer) { static void closeQuietly(MessageProducer producer) {
InputStream message; InputStream message;

View File

@ -34,6 +34,7 @@ import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ChannelLogger; import io.grpc.ChannelLogger;
import io.grpc.ChannelLogger.ChannelLogLevel; import io.grpc.ChannelLogger.ChannelLogLevel;
import io.grpc.ClientStreamTracer;
import io.grpc.ConnectivityState; import io.grpc.ConnectivityState;
import io.grpc.ConnectivityStateInfo; import io.grpc.ConnectivityStateInfo;
import io.grpc.EquivalentAddressGroup; import io.grpc.EquivalentAddressGroup;
@ -667,8 +668,9 @@ final class InternalSubchannel implements InternalInstrumented<ChannelStats>, Tr
@Override @Override
public ClientStream newStream( public ClientStream newStream(
MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions) { MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions,
final ClientStream streamDelegate = super.newStream(method, headers, callOptions); ClientStreamTracer[] tracers) {
final ClientStream streamDelegate = super.newStream(method, headers, callOptions, tracers);
return new ForwardingClientStream() { return new ForwardingClientStream() {
@Override @Override
protected ClientStream delegate() { protected ClientStream delegate() {

View File

@ -532,8 +532,10 @@ final class ManagedChannelImpl extends ManagedChannel implements
ClientTransport transport = ClientTransport transport =
getTransport(new PickSubchannelArgsImpl(method, headers, callOptions)); getTransport(new PickSubchannelArgsImpl(method, headers, callOptions));
Context origContext = context.attach(); Context origContext = context.attach();
ClientStreamTracer[] tracers = GrpcUtil.getClientStreamTracers(
callOptions, headers, /* isTransparentRetry= */ false);
try { try {
return transport.newStream(method, headers, callOptions); return transport.newStream(method, headers, callOptions, tracers);
} finally { } finally {
context.detach(origContext); context.detach(origContext);
} }
@ -569,13 +571,16 @@ final class ManagedChannelImpl extends ManagedChannel implements
} }
@Override @Override
ClientStream newSubstream(ClientStreamTracer.Factory tracerFactory, Metadata newHeaders) { ClientStream newSubstream(
CallOptions newOptions = callOptions.withStreamTracerFactory(tracerFactory); Metadata newHeaders, ClientStreamTracer.Factory factory, boolean isTransparentRetry) {
CallOptions newOptions = callOptions.withStreamTracerFactory(factory);
ClientStreamTracer[] tracers =
GrpcUtil.getClientStreamTracers(newOptions, newHeaders, isTransparentRetry);
ClientTransport transport = ClientTransport transport =
getTransport(new PickSubchannelArgsImpl(method, newHeaders, newOptions)); getTransport(new PickSubchannelArgsImpl(method, newHeaders, newOptions));
Context origContext = context.attach(); Context origContext = context.attach();
try { try {
return transport.newStream(method, newHeaders, newOptions); return transport.newStream(method, newHeaders, newOptions, tracers);
} finally { } finally {
context.detach(origContext); context.detach(origContext);
} }

View File

@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkState;
import io.grpc.CallCredentials.MetadataApplier; import io.grpc.CallCredentials.MetadataApplier;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer;
import io.grpc.Context; import io.grpc.Context;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.MethodDescriptor; import io.grpc.MethodDescriptor;
@ -36,7 +37,7 @@ final class MetadataApplierImpl extends MetadataApplier {
private final CallOptions callOptions; private final CallOptions callOptions;
private final Context ctx; private final Context ctx;
private final MetadataApplierListener listener; private final MetadataApplierListener listener;
private final ClientStreamTracer[] tracers;
private final Object lock = new Object(); private final Object lock = new Object();
// null if neither apply() or returnStream() are called. // null if neither apply() or returnStream() are called.
@ -52,13 +53,14 @@ final class MetadataApplierImpl extends MetadataApplier {
MetadataApplierImpl( MetadataApplierImpl(
ClientTransport transport, MethodDescriptor<?, ?> method, Metadata origHeaders, ClientTransport transport, MethodDescriptor<?, ?> method, Metadata origHeaders,
CallOptions callOptions, MetadataApplierListener listener) { CallOptions callOptions, MetadataApplierListener listener, ClientStreamTracer[] tracers) {
this.transport = transport; this.transport = transport;
this.method = method; this.method = method;
this.origHeaders = origHeaders; this.origHeaders = origHeaders;
this.callOptions = callOptions; this.callOptions = callOptions;
this.ctx = Context.current(); this.ctx = Context.current();
this.listener = listener; this.listener = listener;
this.tracers = tracers;
} }
@Override @Override
@ -69,7 +71,7 @@ final class MetadataApplierImpl extends MetadataApplier {
ClientStream realStream; ClientStream realStream;
Context origCtx = ctx.attach(); Context origCtx = ctx.attach();
try { try {
realStream = transport.newStream(method, origHeaders, callOptions); realStream = transport.newStream(method, origHeaders, callOptions, tracers);
} finally { } finally {
ctx.detach(origCtx); ctx.detach(origCtx);
} }
@ -80,7 +82,7 @@ final class MetadataApplierImpl extends MetadataApplier {
public void fail(Status status) { public void fail(Status status) {
checkArgument(!status.isOk(), "Cannot fail with OK status"); checkArgument(!status.isOk(), "Cannot fail with OK status");
checkState(!finalized, "apply() or fail() already called"); checkState(!finalized, "apply() or fail() already called");
finalizeWith(new FailingClientStream(status)); finalizeWith(new FailingClientStream(status, tracers));
} }
private void finalizeWith(ClientStream stream) { private void finalizeWith(ClientStream stream) {

View File

@ -26,6 +26,7 @@ import com.google.common.util.concurrent.SettableFuture;
import io.grpc.Attributes; import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientCall; import io.grpc.ClientCall;
import io.grpc.ClientStreamTracer;
import io.grpc.ConnectivityState; import io.grpc.ConnectivityState;
import io.grpc.ConnectivityStateInfo; import io.grpc.ConnectivityStateInfo;
import io.grpc.Context; import io.grpc.Context;
@ -86,12 +87,14 @@ final class OobChannel extends ManagedChannel implements InternalInstrumented<Ch
@Override @Override
public ClientStream newStream(MethodDescriptor<?, ?> method, public ClientStream newStream(MethodDescriptor<?, ?> method,
CallOptions callOptions, Metadata headers, Context context) { CallOptions callOptions, Metadata headers, Context context) {
ClientStreamTracer[] tracers = GrpcUtil.getClientStreamTracers(
callOptions, headers, /* isTransparentRetry= */ false);
Context origContext = context.attach(); Context origContext = context.attach();
// delayed transport's newStream() always acquires a lock, but concurrent performance doesn't // delayed transport's newStream() always acquires a lock, but concurrent performance doesn't
// matter here because OOB communication should be sparse, and it's not on application RPC's // matter here because OOB communication should be sparse, and it's not on application RPC's
// critical path. // critical path.
try { try {
return delayedTransport.newStream(method, headers, callOptions); return delayedTransport.newStream(method, headers, callOptions, tracers);
} finally { } finally {
context.detach(origContext); context.detach(origContext);
} }

View File

@ -203,11 +203,11 @@ abstract class RetriableStream<ReqT> implements ClientStream {
} }
} }
private Substream createSubstream(int previousAttemptCount) { private Substream createSubstream(int previousAttemptCount, boolean isTransparentRetry) {
Substream sub = new Substream(previousAttemptCount); Substream sub = new Substream(previousAttemptCount);
// one tracer per substream // one tracer per substream
final ClientStreamTracer bufferSizeTracer = new BufferSizeTracer(sub); final ClientStreamTracer bufferSizeTracer = new BufferSizeTracer(sub);
ClientStreamTracer.Factory tracerFactory = new ClientStreamTracer.Factory() { ClientStreamTracer.Factory tracerFactory = new ClientStreamTracer.InternalLimitedInfoFactory() {
@Override @Override
public ClientStreamTracer newClientStreamTracer( public ClientStreamTracer newClientStreamTracer(
ClientStreamTracer.StreamInfo info, Metadata headers) { ClientStreamTracer.StreamInfo info, Metadata headers) {
@ -217,7 +217,7 @@ abstract class RetriableStream<ReqT> implements ClientStream {
Metadata newHeaders = updateHeaders(headers, previousAttemptCount); Metadata newHeaders = updateHeaders(headers, previousAttemptCount);
// NOTICE: This set _must_ be done before stream.start() and it actually is. // NOTICE: This set _must_ be done before stream.start() and it actually is.
sub.stream = newSubstream(tracerFactory, newHeaders); sub.stream = newSubstream(newHeaders, tracerFactory, isTransparentRetry);
return sub; return sub;
} }
@ -226,7 +226,7 @@ abstract class RetriableStream<ReqT> implements ClientStream {
* Client stream is not yet started. * Client stream is not yet started.
*/ */
abstract ClientStream newSubstream( abstract ClientStream newSubstream(
ClientStreamTracer.Factory tracerFactory, Metadata headers); Metadata headers, ClientStreamTracer.Factory tracerFactory, boolean isTransparentRetry);
/** Adds grpc-previous-rpc-attempts in the headers of a retry/hedging RPC. */ /** Adds grpc-previous-rpc-attempts in the headers of a retry/hedging RPC. */
@VisibleForTesting @VisibleForTesting
@ -322,7 +322,7 @@ abstract class RetriableStream<ReqT> implements ClientStream {
state.buffer.add(new StartEntry()); state.buffer.add(new StartEntry());
} }
Substream substream = createSubstream(0); Substream substream = createSubstream(0, false);
if (isHedging) { if (isHedging) {
FutureCanceller scheduledHedgingRef = null; FutureCanceller scheduledHedgingRef = null;
@ -399,7 +399,7 @@ abstract class RetriableStream<ReqT> implements ClientStream {
// If this run is not cancelled, the value of state.hedgingAttemptCount won't change // If this run is not cancelled, the value of state.hedgingAttemptCount won't change
// until state.addActiveHedge() is called subsequently, even the state could possibly // until state.addActiveHedge() is called subsequently, even the state could possibly
// change. // change.
Substream newSubstream = createSubstream(state.hedgingAttemptCount); Substream newSubstream = createSubstream(state.hedgingAttemptCount, false);
boolean cancelled = false; boolean cancelled = false;
FutureCanceller future = null; FutureCanceller future = null;
@ -784,8 +784,7 @@ abstract class RetriableStream<ReqT> implements ClientStream {
if (rpcProgress == RpcProgress.REFUSED if (rpcProgress == RpcProgress.REFUSED
&& noMoreTransparentRetry.compareAndSet(false, true)) { && noMoreTransparentRetry.compareAndSet(false, true)) {
// transparent retry // transparent retry
final Substream newSubstream = createSubstream( final Substream newSubstream = createSubstream(substream.previousAttemptCount, true);
substream.previousAttemptCount);
if (isHedging) { if (isHedging) {
boolean commit = false; boolean commit = false;
synchronized (lock) { synchronized (lock) {
@ -863,8 +862,9 @@ abstract class RetriableStream<ReqT> implements ClientStream {
@Override @Override
public void run() { public void run() {
// retry // retry
Substream newSubstream = Substream newSubstream = createSubstream(
createSubstream(substream.previousAttemptCount + 1); substream.previousAttemptCount + 1,
false);
drain(newSubstream); drain(newSubstream);
} }
}); });

View File

@ -20,7 +20,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import io.grpc.Attributes; import io.grpc.Attributes;
import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer; import io.grpc.ClientStreamTracer;
import io.grpc.Context; import io.grpc.Context;
import io.grpc.Metadata; import io.grpc.Metadata;
@ -48,21 +47,12 @@ public final class StatsTraceContext {
* Factory method for the client-side. * Factory method for the client-side.
*/ */
public static StatsTraceContext newClientContext( public static StatsTraceContext newClientContext(
final CallOptions callOptions, final Attributes transportAttrs, Metadata headers) { ClientStreamTracer[] tracers, Attributes transportAtts, Metadata headers) {
List<ClientStreamTracer.Factory> factories = callOptions.getStreamTracerFactories(); StatsTraceContext ctx = new StatsTraceContext(tracers);
if (factories.isEmpty()) { for (ClientStreamTracer tracer : tracers) {
return NOOP; tracer.streamCreated(transportAtts, headers);
} }
ClientStreamTracer.StreamInfo info = return ctx;
ClientStreamTracer.StreamInfo.newBuilder()
.setTransportAttrs(transportAttrs).setCallOptions(callOptions).build();
// This array will be iterated multiple times per RPC. Use primitive array instead of Collection
// so that for-each doesn't create an Iterator every time.
StreamTracer[] tracers = new StreamTracer[factories.size()];
for (int i = 0; i < tracers.length; i++) {
tracers[i] = factories.get(i).newClientStreamTracer(info, headers);
}
return new StatsTraceContext(tracers);
} }
/** /**

View File

@ -22,6 +22,7 @@ import com.google.common.annotations.VisibleForTesting;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.Channel; import io.grpc.Channel;
import io.grpc.ClientCall; import io.grpc.ClientCall;
import io.grpc.ClientStreamTracer;
import io.grpc.Context; import io.grpc.Context;
import io.grpc.InternalConfigSelector; import io.grpc.InternalConfigSelector;
import io.grpc.Metadata; import io.grpc.Metadata;
@ -57,9 +58,11 @@ final class SubchannelChannel extends Channel {
if (transport == null) { if (transport == null) {
transport = notReadyTransport; transport = notReadyTransport;
} }
ClientStreamTracer[] tracers = GrpcUtil.getClientStreamTracers(
callOptions, headers, /* isTransparentRetry= */ false);
Context origContext = context.attach(); Context origContext = context.attach();
try { try {
return transport.newStream(method, headers, callOptions); return transport.newStream(method, headers, callOptions, tracers);
} finally { } finally {
context.detach(origContext); context.detach(origContext);
} }

View File

@ -17,6 +17,7 @@
package io.grpc.util; package io.grpc.util;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import io.grpc.Attributes;
import io.grpc.ClientStreamTracer; import io.grpc.ClientStreamTracer;
import io.grpc.ExperimentalApi; import io.grpc.ExperimentalApi;
import io.grpc.Metadata; import io.grpc.Metadata;
@ -27,6 +28,11 @@ public abstract class ForwardingClientStreamTracer extends ClientStreamTracer {
/** Returns the underlying {@code ClientStreamTracer}. */ /** Returns the underlying {@code ClientStreamTracer}. */
protected abstract ClientStreamTracer delegate(); protected abstract ClientStreamTracer delegate();
@Override
public void streamCreated(Attributes transportAttrs, Metadata headers) {
delegate().streamCreated(transportAttrs, headers);
}
@Override @Override
public void outboundHeaders() { public void outboundHeaders() {
delegate().outboundHeaders(); delegate().outboundHeaders();

View File

@ -34,6 +34,7 @@ public class ClientStreamTracerTest {
Attributes.newBuilder().set(TRANSPORT_ATTR_KEY, "value").build(); Attributes.newBuilder().set(TRANSPORT_ATTR_KEY, "value").build();
@Test @Test
@SuppressWarnings("deprecation") // info.getTransportAttrs()
public void streamInfo_empty() { public void streamInfo_empty() {
StreamInfo info = StreamInfo.newBuilder().build(); StreamInfo info = StreamInfo.newBuilder().build();
assertThat(info.getCallOptions()).isSameInstanceAs(CallOptions.DEFAULT); assertThat(info.getCallOptions()).isSameInstanceAs(CallOptions.DEFAULT);
@ -41,6 +42,7 @@ public class ClientStreamTracerTest {
} }
@Test @Test
@SuppressWarnings("deprecation") // info.getTransportAttrs()
public void streamInfo_withInfo() { public void streamInfo_withInfo() {
StreamInfo info = StreamInfo.newBuilder() StreamInfo info = StreamInfo.newBuilder()
.setCallOptions(callOptions).setTransportAttrs(transportAttrs).build(); .setCallOptions(callOptions).setTransportAttrs(transportAttrs).build();
@ -49,6 +51,7 @@ public class ClientStreamTracerTest {
} }
@Test @Test
@SuppressWarnings("deprecation") // info.setTransportAttrs()
public void streamInfo_noEquality() { public void streamInfo_noEquality() {
StreamInfo info1 = StreamInfo.newBuilder() StreamInfo info1 = StreamInfo.newBuilder()
.setCallOptions(callOptions).setTransportAttrs(transportAttrs).build(); .setCallOptions(callOptions).setTransportAttrs(transportAttrs).build();
@ -60,6 +63,7 @@ public class ClientStreamTracerTest {
} }
@Test @Test
@SuppressWarnings("deprecation") // info.getTransportAttrs()
public void streamInfo_toBuilder() { public void streamInfo_toBuilder() {
StreamInfo info1 = StreamInfo.newBuilder() StreamInfo info1 = StreamInfo.newBuilder()
.setCallOptions(callOptions).setTransportAttrs(transportAttrs).build(); .setCallOptions(callOptions).setTransportAttrs(transportAttrs).build();

View File

@ -48,7 +48,6 @@ import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ChannelLogger; import io.grpc.ChannelLogger;
import io.grpc.ClientStreamTracer; import io.grpc.ClientStreamTracer;
import io.grpc.ClientStreamTracer.StreamInfo;
import io.grpc.Grpc; import io.grpc.Grpc;
import io.grpc.InternalChannelz.SocketStats; import io.grpc.InternalChannelz.SocketStats;
import io.grpc.InternalChannelz.TransportStats; import io.grpc.InternalChannelz.TransportStats;
@ -172,7 +171,7 @@ public abstract class AbstractTransportTest {
.setRequestMarshaller(StringMarshaller.INSTANCE) .setRequestMarshaller(StringMarshaller.INSTANCE)
.setResponseMarshaller(StringMarshaller.INSTANCE) .setResponseMarshaller(StringMarshaller.INSTANCE)
.build(); .build();
private CallOptions callOptions; private final CallOptions callOptions = CallOptions.DEFAULT;
private Metadata.Key<String> asciiKey = Metadata.Key.of( private Metadata.Key<String> asciiKey = Metadata.Key.of(
"ascii-key", Metadata.ASCII_STRING_MARSHALLER); "ascii-key", Metadata.ASCII_STRING_MARSHALLER);
@ -186,24 +185,14 @@ public abstract class AbstractTransportTest {
= mock(ManagedClientTransport.Listener.class); = mock(ManagedClientTransport.Listener.class);
private MockServerListener serverListener = new MockServerListener(); private MockServerListener serverListener = new MockServerListener();
private ArgumentCaptor<Throwable> throwableCaptor = ArgumentCaptor.forClass(Throwable.class); private ArgumentCaptor<Throwable> throwableCaptor = ArgumentCaptor.forClass(Throwable.class);
private final TestClientStreamTracer clientStreamTracer1 = new TestClientStreamTracer(); private final TestClientStreamTracer clientStreamTracer1 = new TestHeaderClientStreamTracer();
private final TestClientStreamTracer clientStreamTracer2 = new TestClientStreamTracer(); private final TestClientStreamTracer clientStreamTracer2 = new TestHeaderClientStreamTracer();
private final ClientStreamTracer.Factory clientStreamTracerFactory = mock( private final ClientStreamTracer[] tracers = new ClientStreamTracer[] {
ClientStreamTracer.Factory.class, clientStreamTracer1, clientStreamTracer2
delegatesTo(new ClientStreamTracer.Factory() { };
final ArrayDeque<TestClientStreamTracer> tracers = private final ClientStreamTracer[] noopTracers = new ClientStreamTracer[] {
new ArrayDeque<>(Arrays.asList(clientStreamTracer1, clientStreamTracer2)); new ClientStreamTracer() {}
};
@Override
public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata metadata) {
metadata.put(tracerHeaderKey, tracerKeyValue);
TestClientStreamTracer tracer = tracers.poll();
if (tracer != null) {
return tracer;
}
return new TestClientStreamTracer();
}
}));
private final TestServerStreamTracer serverStreamTracer1 = new TestServerStreamTracer(); private final TestServerStreamTracer serverStreamTracer1 = new TestServerStreamTracer();
private final TestServerStreamTracer serverStreamTracer2 = new TestServerStreamTracer(); private final TestServerStreamTracer serverStreamTracer2 = new TestServerStreamTracer();
@ -230,7 +219,6 @@ public abstract class AbstractTransportTest {
@Before @Before
public void setUp() { public void setUp() {
server = newServer(Arrays.asList(serverStreamTracerFactory)); server = newServer(Arrays.asList(serverStreamTracerFactory));
callOptions = CallOptions.DEFAULT.withStreamTracerFactory(clientStreamTracerFactory);
} }
@After @After
@ -291,7 +279,8 @@ public abstract class AbstractTransportTest {
// after having sent a RST_STREAM to the server. Previously, this would have broken the // after having sent a RST_STREAM to the server. Previously, this would have broken the
// Netty channel. // Netty channel.
ClientStream stream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream stream = client.newStream(
methodDescriptor, new Metadata(), callOptions, noopTracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
stream.start(clientStreamListener); stream.start(clientStreamListener);
StreamCreation serverStreamCreation StreamCreation serverStreamCreation
@ -314,7 +303,8 @@ public abstract class AbstractTransportTest {
// Test that the channel is still usable i.e. we can receive headers from the server on a // Test that the channel is still usable i.e. we can receive headers from the server on a
// new stream. // new stream.
stream = client.newStream(methodDescriptor, new Metadata(), callOptions); stream = client.newStream(
methodDescriptor, new Metadata(), callOptions, noopTracers);
stream.start(mockClientStreamListener2); stream.start(mockClientStreamListener2);
serverStreamCreation serverStreamCreation
= serverTransportListener.takeStreamOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS); = serverTransportListener.takeStreamOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
@ -449,7 +439,8 @@ public abstract class AbstractTransportTest {
= serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS); = serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
serverTransport = serverTransportListener.transport; serverTransport = serverTransportListener.transport;
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportInUse(true); verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportInUse(true);
@ -501,7 +492,8 @@ public abstract class AbstractTransportTest {
= serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS); = serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
serverTransport = serverTransportListener.transport; serverTransport = serverTransportListener.transport;
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportInUse(true); verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportInUse(true);
@ -539,7 +531,8 @@ public abstract class AbstractTransportTest {
= serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS); = serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
serverTransport = serverTransportListener.transport; serverTransport = serverTransportListener.transport;
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportInUse(true); verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportInUse(true);
@ -594,7 +587,8 @@ public abstract class AbstractTransportTest {
client = newClientTransport(server); client = newClientTransport(server);
startTransport(client, mockClientTransportListener); startTransport(client, mockClientTransportListener);
// Stream prevents termination // Stream prevents termination
ClientStream stream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream stream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
stream.start(clientStreamListener); stream.start(clientStreamListener);
client.shutdown(Status.UNAVAILABLE); client.shutdown(Status.UNAVAILABLE);
@ -633,22 +627,19 @@ public abstract class AbstractTransportTest {
@Test @Test
public void newStream_duringShutdown() throws Exception { public void newStream_duringShutdown() throws Exception {
InOrder inOrder = inOrder(clientStreamTracerFactory);
server.start(serverListener); server.start(serverListener);
client = newClientTransport(server); client = newClientTransport(server);
startTransport(client, mockClientTransportListener); startTransport(client, mockClientTransportListener);
// Stream prevents termination // Stream prevents termination
ClientStream stream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream stream = client.newStream(
inOrder.verify(clientStreamTracerFactory).newClientStreamTracer( methodDescriptor, new Metadata(), callOptions, noopTracers);
any(ClientStreamTracer.StreamInfo.class), any(Metadata.class));
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
stream.start(clientStreamListener); stream.start(clientStreamListener);
client.shutdown(Status.UNAVAILABLE); client.shutdown(Status.UNAVAILABLE);
verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportShutdown(any(Status.class)); verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportShutdown(any(Status.class));
ClientStream stream2 = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream stream2 = client.newStream(
inOrder.verify(clientStreamTracerFactory).newClientStreamTracer( methodDescriptor, new Metadata(), callOptions, tracers);
any(ClientStreamTracer.StreamInfo.class), any(Metadata.class));
ClientStreamListenerBase clientStreamListener2 = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener2 = new ClientStreamListenerBase();
stream2.start(clientStreamListener2); stream2.start(clientStreamListener2);
Status clientStreamStatus2 = Status clientStreamStatus2 =
@ -683,15 +674,14 @@ public abstract class AbstractTransportTest {
client.shutdown(shutdownReason); client.shutdown(shutdownReason);
verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportTerminated(); verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportTerminated();
Thread.sleep(100); Thread.sleep(100);
ClientStream stream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream stream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
stream.start(clientStreamListener); stream.start(clientStreamListener);
assertEquals( assertEquals(
shutdownReason, clientStreamListener.status.get(TIMEOUT_MS, TimeUnit.MILLISECONDS)); shutdownReason, clientStreamListener.status.get(TIMEOUT_MS, TimeUnit.MILLISECONDS));
assertNotNull(clientStreamListener.trailers.get(TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertNotNull(clientStreamListener.trailers.get(TIMEOUT_MS, TimeUnit.MILLISECONDS));
verify(mockClientTransportListener, never()).transportInUse(anyBoolean()); verify(mockClientTransportListener, never()).transportInUse(anyBoolean());
verify(clientStreamTracerFactory).newClientStreamTracer(
any(ClientStreamTracer.StreamInfo.class), any(Metadata.class));
assertNull(clientStreamTracer1.getInboundTrailers()); assertNull(clientStreamTracer1.getInboundTrailers());
assertSame(shutdownReason, clientStreamTracer1.getStatus()); assertSame(shutdownReason, clientStreamTracer1.getStatus());
// Assert no interactions // Assert no interactions
@ -708,7 +698,8 @@ public abstract class AbstractTransportTest {
// CALL_OPTIONS_RPC_OWNED_BY_BALANCER in CallOptions. It won't be counted for in-use signal. // CALL_OPTIONS_RPC_OWNED_BY_BALANCER in CallOptions. It won't be counted for in-use signal.
ClientStream stream1 = client.newStream( ClientStream stream1 = client.newStream(
methodDescriptor, new Metadata(), methodDescriptor, new Metadata(),
callOptions.withOption(GrpcUtil.CALL_OPTIONS_RPC_OWNED_BY_BALANCER, Boolean.TRUE)); callOptions.withOption(GrpcUtil.CALL_OPTIONS_RPC_OWNED_BY_BALANCER, Boolean.TRUE),
noopTracers);
ClientStreamListenerBase clientStreamListener1 = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener1 = new ClientStreamListenerBase();
stream1.start(clientStreamListener1); stream1.start(clientStreamListener1);
MockServerTransportListener serverTransportListener MockServerTransportListener serverTransportListener
@ -717,7 +708,8 @@ public abstract class AbstractTransportTest {
= serverTransportListener.takeStreamOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS); = serverTransportListener.takeStreamOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
// stream2 is the normal RPC, and will be counted for in-use // stream2 is the normal RPC, and will be counted for in-use
ClientStream stream2 = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream stream2 = client.newStream(
methodDescriptor, new Metadata(), callOptions, noopTracers);
ClientStreamListenerBase clientStreamListener2 = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener2 = new ClientStreamListenerBase();
stream2.start(clientStreamListener2); stream2.start(clientStreamListener2);
verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportInUse(true); verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportInUse(true);
@ -743,7 +735,8 @@ public abstract class AbstractTransportTest {
server.start(serverListener); server.start(serverListener);
client = newClientTransport(server); client = newClientTransport(server);
startTransport(client, mockClientTransportListener); startTransport(client, mockClientTransportListener);
ClientStream stream1 = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream stream1 = client.newStream(
methodDescriptor, new Metadata(), callOptions, noopTracers);
ClientStreamListenerBase clientStreamListener1 = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener1 = new ClientStreamListenerBase();
stream1.start(clientStreamListener1); stream1.start(clientStreamListener1);
verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportInUse(true); verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportInUse(true);
@ -751,7 +744,8 @@ public abstract class AbstractTransportTest {
= serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS); = serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
StreamCreation serverStreamCreation1 StreamCreation serverStreamCreation1
= serverTransportListener.takeStreamOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS); = serverTransportListener.takeStreamOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
ClientStream stream2 = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream stream2 = client.newStream(
methodDescriptor, new Metadata(), callOptions, noopTracers);
ClientStreamListenerBase clientStreamListener2 = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener2 = new ClientStreamListenerBase();
stream2.start(clientStreamListener2); stream2.start(clientStreamListener2);
StreamCreation serverStreamCreation2 StreamCreation serverStreamCreation2
@ -773,11 +767,13 @@ public abstract class AbstractTransportTest {
server.start(serverListener); server.start(serverListener);
client = newClientTransport(server); client = newClientTransport(server);
startTransport(client, mockClientTransportListener); startTransport(client, mockClientTransportListener);
ClientStream stream1 = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream stream1 = client.newStream(
methodDescriptor, new Metadata(), callOptions, noopTracers);
ClientStreamListenerBase clientStreamListener1 = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener1 = new ClientStreamListenerBase();
stream1.start(clientStreamListener1); stream1.start(clientStreamListener1);
verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportInUse(true); verify(mockClientTransportListener, timeout(TIMEOUT_MS)).transportInUse(true);
ClientStream stream2 = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream stream2 = client.newStream(
methodDescriptor, new Metadata(), callOptions, noopTracers);
ClientStreamListenerBase clientStreamListener2 = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener2 = new ClientStreamListenerBase();
stream2.start(clientStreamListener2); stream2.start(clientStreamListener2);
@ -792,7 +788,6 @@ public abstract class AbstractTransportTest {
@Test @Test
public void basicStream() throws Exception { public void basicStream() throws Exception {
InOrder clientInOrder = inOrder(clientStreamTracerFactory);
InOrder serverInOrder = inOrder(serverStreamTracerFactory); InOrder serverInOrder = inOrder(serverStreamTracerFactory);
server.start(serverListener); server.start(serverListener);
client = newClientTransport(server); client = newClientTransport(server);
@ -816,14 +811,10 @@ public abstract class AbstractTransportTest {
Metadata clientHeadersCopy = new Metadata(); Metadata clientHeadersCopy = new Metadata();
clientHeadersCopy.merge(clientHeaders); clientHeadersCopy.merge(clientHeaders);
ClientStream clientStream = client.newStream(methodDescriptor, clientHeaders, callOptions); ClientStream clientStream = client.newStream(
ArgumentCaptor<ClientStreamTracer.StreamInfo> streamInfoCaptor = ArgumentCaptor.forClass(null); methodDescriptor, clientHeaders, callOptions, tracers);
clientInOrder.verify(clientStreamTracerFactory).newClientStreamTracer( assertThat(((TestHeaderClientStreamTracer) clientStreamTracer1).transportAttrs)
streamInfoCaptor.capture(), same(clientHeaders)); .isSameInstanceAs(((ConnectionClientTransport) client).getAttributes());
ClientStreamTracer.StreamInfo streamInfo = streamInfoCaptor.getValue();
assertThat(streamInfo.getTransportAttrs()).isSameInstanceAs(
((ConnectionClientTransport) client).getAttributes());
assertThat(streamInfo.getCallOptions()).isSameInstanceAs(callOptions);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
@ -974,7 +965,8 @@ public abstract class AbstractTransportTest {
= serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS); = serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
Metadata clientHeaders = new Metadata(); Metadata clientHeaders = new Metadata();
ClientStream clientStream = client.newStream(methodDescriptor, clientHeaders, callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, clientHeaders, callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
StreamCreation serverStreamCreation StreamCreation serverStreamCreation
@ -1005,7 +997,8 @@ public abstract class AbstractTransportTest {
= serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS); = serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
serverTransport = serverTransportListener.transport; serverTransport = serverTransportListener.transport;
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
StreamCreation serverStreamCreation StreamCreation serverStreamCreation
@ -1044,7 +1037,8 @@ public abstract class AbstractTransportTest {
= serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS); = serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
serverTransport = serverTransportListener.transport; serverTransport = serverTransportListener.transport;
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
StreamCreation serverStreamCreation StreamCreation serverStreamCreation
@ -1080,7 +1074,8 @@ public abstract class AbstractTransportTest {
= serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS); = serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
serverTransport = serverTransportListener.transport; serverTransport = serverTransportListener.transport;
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
StreamCreation serverStreamCreation StreamCreation serverStreamCreation
@ -1122,7 +1117,8 @@ public abstract class AbstractTransportTest {
= serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS); = serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
serverTransport = serverTransportListener.transport; serverTransport = serverTransportListener.transport;
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
StreamCreation serverStreamCreation StreamCreation serverStreamCreation
@ -1155,7 +1151,8 @@ public abstract class AbstractTransportTest {
serverTransport = serverTransportListener.transport; serverTransport = serverTransportListener.transport;
final ClientStream clientStream = final ClientStream clientStream =
client.newStream(methodDescriptor, new Metadata(), callOptions); client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase() { ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase() {
@Override @Override
@ -1196,7 +1193,8 @@ public abstract class AbstractTransportTest {
= serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS); = serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
serverTransport = serverTransportListener.transport; serverTransport = serverTransportListener.transport;
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
StreamCreation serverStreamCreation StreamCreation serverStreamCreation
@ -1230,7 +1228,8 @@ public abstract class AbstractTransportTest {
final SettableFuture<Boolean> closedCalled = SettableFuture.create(); final SettableFuture<Boolean> closedCalled = SettableFuture.create();
final ClientStream clientStream = final ClientStream clientStream =
client.newStream(methodDescriptor, new Metadata(), callOptions); client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
final Status status = Status.CANCELLED.withDescription("nevermind"); final Status status = Status.CANCELLED.withDescription("nevermind");
clientStream.start(new ClientStreamListener() { clientStream.start(new ClientStreamListener() {
private boolean messageReceived = false; private boolean messageReceived = false;
@ -1311,7 +1310,8 @@ public abstract class AbstractTransportTest {
= serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS); = serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
serverTransport = serverTransportListener.transport; serverTransport = serverTransportListener.transport;
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
StreamCreation serverStreamCreation StreamCreation serverStreamCreation
@ -1331,8 +1331,6 @@ public abstract class AbstractTransportTest {
// Cause should not be transmitted between server and client // Cause should not be transmitted between server and client
assertNull(clientStreamStatus.getCause()); assertNull(clientStreamStatus.getCause());
verify(clientStreamTracerFactory).newClientStreamTracer(
any(ClientStreamTracer.StreamInfo.class), any(Metadata.class));
assertTrue(clientStreamTracer1.getOutboundHeaders()); assertTrue(clientStreamTracer1.getOutboundHeaders());
assertNull(clientStreamTracer1.getInboundTrailers()); assertNull(clientStreamTracer1.getInboundTrailers());
assertSame(clientStreamStatus, clientStreamTracer1.getStatus()); assertSame(clientStreamStatus, clientStreamTracer1.getStatus());
@ -1353,7 +1351,8 @@ public abstract class AbstractTransportTest {
serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS); serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
serverTransport = serverTransportListener.transport; serverTransport = serverTransportListener.transport;
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
StreamCreation serverStreamCreation = StreamCreation serverStreamCreation =
@ -1515,7 +1514,8 @@ public abstract class AbstractTransportTest {
// boilerplate // boilerplate
ClientStream clientStream = ClientStream clientStream =
client.newStream(methodDescriptor, new Metadata(), callOptions); client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
StreamCreation server StreamCreation server
@ -1547,7 +1547,8 @@ public abstract class AbstractTransportTest {
// boilerplate // boilerplate
ClientStream clientStream = ClientStream clientStream =
client.newStream(methodDescriptor, new Metadata(), callOptions); client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListener clientListener = mock(ClientStreamListener.class); ClientStreamListener clientListener = mock(ClientStreamListener.class);
clientStream.start(clientListener); clientStream.start(clientListener);
StreamCreation server StreamCreation server
@ -1594,7 +1595,8 @@ public abstract class AbstractTransportTest {
assertEquals(0, clientBefore.streamsStarted); assertEquals(0, clientBefore.streamsStarted);
assertEquals(0, clientBefore.lastRemoteStreamCreatedTimeNanos); assertEquals(0, clientBefore.lastRemoteStreamCreatedTimeNanos);
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
StreamCreation serverStreamCreation = serverTransportListener StreamCreation serverStreamCreation = serverTransportListener
@ -1624,7 +1626,8 @@ public abstract class AbstractTransportTest {
TransportStats clientBefore = getTransportStats(client); TransportStats clientBefore = getTransportStats(client);
assertEquals(1, clientBefore.streamsStarted); assertEquals(1, clientBefore.streamsStarted);
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, noopTracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
StreamCreation serverStreamCreation = serverTransportListener StreamCreation serverStreamCreation = serverTransportListener
@ -1654,7 +1657,8 @@ public abstract class AbstractTransportTest {
server.start(serverListener); server.start(serverListener);
client = newClientTransport(server); client = newClientTransport(server);
startTransport(client, mockClientTransportListener); startTransport(client, mockClientTransportListener);
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
MockServerTransportListener serverTransportListener MockServerTransportListener serverTransportListener
@ -1693,7 +1697,8 @@ public abstract class AbstractTransportTest {
server.start(serverListener); server.start(serverListener);
client = newClientTransport(server); client = newClientTransport(server);
startTransport(client, mockClientTransportListener); startTransport(client, mockClientTransportListener);
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
MockServerTransportListener serverTransportListener MockServerTransportListener serverTransportListener
@ -1733,7 +1738,8 @@ public abstract class AbstractTransportTest {
server.start(serverListener); server.start(serverListener);
client = newClientTransport(server); client = newClientTransport(server);
startTransport(client, mockClientTransportListener); startTransport(client, mockClientTransportListener);
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
MockServerTransportListener serverTransportListener = MockServerTransportListener serverTransportListener =
@ -1768,7 +1774,8 @@ public abstract class AbstractTransportTest {
server.start(serverListener); server.start(serverListener);
client = newClientTransport(server); client = newClientTransport(server);
startTransport(client, mockClientTransportListener); startTransport(client, mockClientTransportListener);
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
MockServerTransportListener serverTransportListener MockServerTransportListener serverTransportListener
@ -1809,7 +1816,8 @@ public abstract class AbstractTransportTest {
server.start(serverListener); server.start(serverListener);
client = newClientTransport(server); client = newClientTransport(server);
startTransport(client, mockClientTransportListener); startTransport(client, mockClientTransportListener);
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
MockServerTransportListener serverTransportListener MockServerTransportListener serverTransportListener
@ -1849,7 +1857,8 @@ public abstract class AbstractTransportTest {
server.start(serverListener); server.start(serverListener);
ManagedClientTransport client = newClientTransport(server); ManagedClientTransport client = newClientTransport(server);
startTransport(client, mockClientTransportListener); startTransport(client, mockClientTransportListener);
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
@ -1896,8 +1905,8 @@ public abstract class AbstractTransportTest {
Metadata.Key.of("foo-bin", Metadata.BINARY_BYTE_MARSHALLER), Metadata.Key.of("foo-bin", Metadata.BINARY_BYTE_MARSHALLER),
new byte[GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE]); new byte[GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE]);
ClientStream clientStream = ClientStream clientStream = client.newStream(
client.newStream(methodDescriptor, tooLargeMetadata, callOptions); methodDescriptor, tooLargeMetadata, callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
@ -1931,7 +1940,8 @@ public abstract class AbstractTransportTest {
new byte[GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE]); new byte[GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE]);
ClientStream clientStream = ClientStream clientStream =
client.newStream(methodDescriptor, new Metadata(), callOptions); client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
@ -1975,7 +1985,8 @@ public abstract class AbstractTransportTest {
new byte[GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE]); new byte[GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE]);
ClientStream clientStream = ClientStream clientStream =
client.newStream(methodDescriptor, new Metadata(), callOptions); client.newStream(
methodDescriptor, new Metadata(), callOptions, tracers);
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
@ -2011,7 +2022,9 @@ public abstract class AbstractTransportTest {
ManagedClientTransport client = newClientTransport(server); ManagedClientTransport client = newClientTransport(server);
ManagedClientTransport.Listener listener = mock(ManagedClientTransport.Listener.class); ManagedClientTransport.Listener listener = mock(ManagedClientTransport.Listener.class);
startTransport(client, listener); startTransport(client, listener);
ClientStream clientStream = client.newStream(methodDescriptor, new Metadata(), callOptions); ClientStream clientStream = client.newStream(
methodDescriptor, new Metadata(), callOptions,
new ClientStreamTracer[] { new ClientStreamTracer() {} });
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase(); ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase();
clientStream.start(clientStreamListener); clientStream.start(clientStreamListener);
@ -2092,6 +2105,16 @@ public abstract class AbstractTransportTest {
verify(listener, timeout(TIMEOUT_MS)).transportReady(); verify(listener, timeout(TIMEOUT_MS)).transportReady();
} }
private final class TestHeaderClientStreamTracer extends TestClientStreamTracer {
Attributes transportAttrs;
@Override
public void streamCreated(Attributes transportAttrs, Metadata metadata) {
this.transportAttrs = transportAttrs;
metadata.put(tracerHeaderKey, tracerKeyValue);
}
}
private static class MockServerListener implements ServerListener { private static class MockServerListener implements ServerListener {
public final BlockingQueue<MockServerTransportListener> listeners public final BlockingQueue<MockServerTransportListener> listeners
= new LinkedBlockingQueue<>(); = new LinkedBlockingQueue<>();

View File

@ -34,6 +34,7 @@ import io.grpc.CallCredentials.MetadataApplier;
import io.grpc.CallCredentials.RequestInfo; import io.grpc.CallCredentials.RequestInfo;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ChannelLogger; import io.grpc.ChannelLogger;
import io.grpc.ClientStreamTracer;
import io.grpc.IntegerMarshaller; import io.grpc.IntegerMarshaller;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.MethodDescriptor; import io.grpc.MethodDescriptor;
@ -48,6 +49,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.JUnit4; import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoJUnit;
@ -103,6 +105,9 @@ public class CallCredentials2ApplyingTest {
private static final Metadata.Key<String> CREDS_KEY = private static final Metadata.Key<String> CREDS_KEY =
Metadata.Key.of("test-creds", Metadata.ASCII_STRING_MARSHALLER); Metadata.Key.of("test-creds", Metadata.ASCII_STRING_MARSHALLER);
private static final String CREDS_VALUE = "some credentials"; private static final String CREDS_VALUE = "some credentials";
private static final ClientStreamTracer[] tracers = new ClientStreamTracer[] {
new ClientStreamTracer() {}
};
private final Metadata origHeaders = new Metadata(); private final Metadata origHeaders = new Metadata();
private ForwardingConnectionClientTransport transport; private ForwardingConnectionClientTransport transport;
@ -118,7 +123,9 @@ public class CallCredentials2ApplyingTest {
origHeaders.put(ORIG_HEADER_KEY, ORIG_HEADER_VALUE); origHeaders.put(ORIG_HEADER_KEY, ORIG_HEADER_VALUE);
when(mockTransportFactory.newClientTransport(address, clientTransportOptions, channelLogger)) when(mockTransportFactory.newClientTransport(address, clientTransportOptions, channelLogger))
.thenReturn(mockTransport); .thenReturn(mockTransport);
when(mockTransport.newStream(same(method), any(Metadata.class), any(CallOptions.class))) when(mockTransport.newStream(
same(method), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream); .thenReturn(mockStream);
ClientTransportFactory transportFactory = new CallCredentialsApplyingTransportFactory( ClientTransportFactory transportFactory = new CallCredentialsApplyingTransportFactory(
mockTransportFactory, null, mockExecutor); mockTransportFactory, null, mockExecutor);
@ -134,7 +141,7 @@ public class CallCredentials2ApplyingTest {
Attributes transportAttrs = Attributes.newBuilder().set(ATTR_KEY, ATTR_VALUE).build(); Attributes transportAttrs = Attributes.newBuilder().set(ATTR_KEY, ATTR_VALUE).build();
when(mockTransport.getAttributes()).thenReturn(transportAttrs); when(mockTransport.getAttributes()).thenReturn(transportAttrs);
transport.newStream(method, origHeaders, callOptions); transport.newStream(method, origHeaders, callOptions, tracers);
ArgumentCaptor<RequestInfo> infoCaptor = ArgumentCaptor.forClass(null); ArgumentCaptor<RequestInfo> infoCaptor = ArgumentCaptor.forClass(null);
verify(mockCreds).applyRequestMetadata( verify(mockCreds).applyRequestMetadata(
@ -155,7 +162,7 @@ public class CallCredentials2ApplyingTest {
.build(); .build();
when(mockTransport.getAttributes()).thenReturn(transportAttrs); when(mockTransport.getAttributes()).thenReturn(transportAttrs);
transport.newStream(method, origHeaders, callOptions); transport.newStream(method, origHeaders, callOptions, tracers);
ArgumentCaptor<RequestInfo> infoCaptor = ArgumentCaptor.forClass(null); ArgumentCaptor<RequestInfo> infoCaptor = ArgumentCaptor.forClass(null);
verify(mockCreds).applyRequestMetadata( verify(mockCreds).applyRequestMetadata(
@ -176,8 +183,10 @@ public class CallCredentials2ApplyingTest {
when(mockTransport.getAttributes()).thenReturn(transportAttrs); when(mockTransport.getAttributes()).thenReturn(transportAttrs);
Executor anotherExecutor = mock(Executor.class); Executor anotherExecutor = mock(Executor.class);
transport.newStream(method, origHeaders, transport.newStream(
callOptions.withAuthority("calloptions-authority").withExecutor(anotherExecutor)); method, origHeaders,
callOptions.withAuthority("calloptions-authority").withExecutor(anotherExecutor),
tracers);
ArgumentCaptor<RequestInfo> infoCaptor = ArgumentCaptor.forClass(null); ArgumentCaptor<RequestInfo> infoCaptor = ArgumentCaptor.forClass(null);
verify(mockCreds).applyRequestMetadata( verify(mockCreds).applyRequestMetadata(
@ -199,13 +208,15 @@ public class CallCredentials2ApplyingTest {
any(io.grpc.CallCredentials2.MetadataApplier.class)); any(io.grpc.CallCredentials2.MetadataApplier.class));
FailingClientStream stream = FailingClientStream stream =
(FailingClientStream) transport.newStream(method, origHeaders, callOptions); (FailingClientStream) transport.newStream(method, origHeaders, callOptions, tracers);
verify(mockTransport, never()).newStream(method, origHeaders, callOptions); verify(mockTransport, never()).newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
assertEquals(Status.Code.UNAUTHENTICATED, stream.getError().getCode()); assertEquals(Status.Code.UNAUTHENTICATED, stream.getError().getCode());
assertSame(ex, stream.getError().getCause()); assertSame(ex, stream.getError().getCause());
transport.shutdown(Status.UNAVAILABLE); transport.shutdown(Status.UNAVAILABLE);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport).shutdown(Status.UNAVAILABLE); verify(mockTransport).shutdown(Status.UNAVAILABLE);
} }
@ -226,14 +237,14 @@ public class CallCredentials2ApplyingTest {
any(RequestInfo.class), same(mockExecutor), any(RequestInfo.class), same(mockExecutor),
any(io.grpc.CallCredentials2.MetadataApplier.class)); any(io.grpc.CallCredentials2.MetadataApplier.class));
ClientStream stream = transport.newStream(method, origHeaders, callOptions); ClientStream stream = transport.newStream(method, origHeaders, callOptions, tracers);
verify(mockTransport).newStream(method, origHeaders, callOptions); verify(mockTransport).newStream(method, origHeaders, callOptions, tracers);
assertSame(mockStream, stream); assertSame(mockStream, stream);
assertEquals(CREDS_VALUE, origHeaders.get(CREDS_KEY)); assertEquals(CREDS_VALUE, origHeaders.get(CREDS_KEY));
assertEquals(ORIG_HEADER_VALUE, origHeaders.get(ORIG_HEADER_KEY)); assertEquals(ORIG_HEADER_VALUE, origHeaders.get(ORIG_HEADER_KEY));
transport.shutdown(Status.UNAVAILABLE); transport.shutdown(Status.UNAVAILABLE);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport).shutdown(Status.UNAVAILABLE); verify(mockTransport).shutdown(Status.UNAVAILABLE);
} }
@ -254,12 +265,14 @@ public class CallCredentials2ApplyingTest {
any(io.grpc.CallCredentials2.MetadataApplier.class)); any(io.grpc.CallCredentials2.MetadataApplier.class));
FailingClientStream stream = FailingClientStream stream =
(FailingClientStream) transport.newStream(method, origHeaders, callOptions); (FailingClientStream) transport.newStream(method, origHeaders, callOptions, tracers);
verify(mockTransport, never()).newStream(method, origHeaders, callOptions); verify(mockTransport, never()).newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
assertSame(error, stream.getError()); assertSame(error, stream.getError());
transport.shutdownNow(Status.UNAVAILABLE); transport.shutdownNow(Status.UNAVAILABLE);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport).shutdownNow(Status.UNAVAILABLE); verify(mockTransport).shutdownNow(Status.UNAVAILABLE);
} }
@ -269,12 +282,15 @@ public class CallCredentials2ApplyingTest {
when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY); when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY);
// Will call applyRequestMetadata(), which is no-op. // Will call applyRequestMetadata(), which is no-op.
DelayedStream stream = (DelayedStream) transport.newStream(method, origHeaders, callOptions); DelayedStream stream = (DelayedStream) transport.newStream(
method, origHeaders, callOptions, tracers);
ArgumentCaptor<MetadataApplier> applierCaptor = ArgumentCaptor.forClass(null); ArgumentCaptor<MetadataApplier> applierCaptor = ArgumentCaptor.forClass(null);
verify(mockCreds).applyRequestMetadata( verify(mockCreds).applyRequestMetadata(
any(RequestInfo.class), same(mockExecutor), applierCaptor.capture()); any(RequestInfo.class), same(mockExecutor), applierCaptor.capture());
verify(mockTransport, never()).newStream(method, origHeaders, callOptions); verify(mockTransport, never()).newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
transport.shutdown(Status.UNAVAILABLE); transport.shutdown(Status.UNAVAILABLE);
verify(mockTransport, never()).shutdown(Status.UNAVAILABLE); verify(mockTransport, never()).shutdown(Status.UNAVAILABLE);
@ -283,11 +299,11 @@ public class CallCredentials2ApplyingTest {
headers.put(CREDS_KEY, CREDS_VALUE); headers.put(CREDS_KEY, CREDS_VALUE);
applierCaptor.getValue().apply(headers); applierCaptor.getValue().apply(headers);
verify(mockTransport).newStream(method, origHeaders, callOptions); verify(mockTransport).newStream(method, origHeaders, callOptions, tracers);
assertSame(mockStream, stream.getRealStream()); assertSame(mockStream, stream.getRealStream());
assertEquals(CREDS_VALUE, origHeaders.get(CREDS_KEY)); assertEquals(CREDS_VALUE, origHeaders.get(CREDS_KEY));
assertEquals(ORIG_HEADER_VALUE, origHeaders.get(ORIG_HEADER_KEY)); assertEquals(ORIG_HEADER_VALUE, origHeaders.get(ORIG_HEADER_KEY));
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport).shutdown(Status.UNAVAILABLE); verify(mockTransport).shutdown(Status.UNAVAILABLE);
} }
@ -297,7 +313,8 @@ public class CallCredentials2ApplyingTest {
when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY); when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY);
// Will call applyRequestMetadata(), which is no-op. // Will call applyRequestMetadata(), which is no-op.
DelayedStream stream = (DelayedStream) transport.newStream(method, origHeaders, callOptions); DelayedStream stream = (DelayedStream) transport.newStream(
method, origHeaders, callOptions, tracers);
ArgumentCaptor<MetadataApplier> applierCaptor = ArgumentCaptor.forClass(null); ArgumentCaptor<MetadataApplier> applierCaptor = ArgumentCaptor.forClass(null);
verify(mockCreds).applyRequestMetadata( verify(mockCreds).applyRequestMetadata(
@ -306,11 +323,13 @@ public class CallCredentials2ApplyingTest {
Status error = Status.FAILED_PRECONDITION.withDescription("channel not secure for creds"); Status error = Status.FAILED_PRECONDITION.withDescription("channel not secure for creds");
applierCaptor.getValue().fail(error); applierCaptor.getValue().fail(error);
verify(mockTransport, never()).newStream(method, origHeaders, callOptions); verify(mockTransport, never()).newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
FailingClientStream failingStream = (FailingClientStream) stream.getRealStream(); FailingClientStream failingStream = (FailingClientStream) stream.getRealStream();
assertSame(error, failingStream.getError()); assertSame(error, failingStream.getError());
transport.shutdown(Status.UNAVAILABLE); transport.shutdown(Status.UNAVAILABLE);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport).shutdown(Status.UNAVAILABLE); verify(mockTransport).shutdown(Status.UNAVAILABLE);
} }
@ -318,14 +337,14 @@ public class CallCredentials2ApplyingTest {
@Test @Test
public void noCreds() { public void noCreds() {
callOptions = callOptions.withCallCredentials(null); callOptions = callOptions.withCallCredentials(null);
ClientStream stream = transport.newStream(method, origHeaders, callOptions); ClientStream stream = transport.newStream(method, origHeaders, callOptions, tracers);
verify(mockTransport).newStream(method, origHeaders, callOptions); verify(mockTransport).newStream(method, origHeaders, callOptions, tracers);
assertSame(mockStream, stream); assertSame(mockStream, stream);
assertNull(origHeaders.get(CREDS_KEY)); assertNull(origHeaders.get(CREDS_KEY));
assertEquals(ORIG_HEADER_VALUE, origHeaders.get(ORIG_HEADER_KEY)); assertEquals(ORIG_HEADER_VALUE, origHeaders.get(ORIG_HEADER_KEY));
transport.shutdown(Status.UNAVAILABLE); transport.shutdown(Status.UNAVAILABLE);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport).shutdown(Status.UNAVAILABLE); verify(mockTransport).shutdown(Status.UNAVAILABLE);
} }

View File

@ -35,6 +35,7 @@ import io.grpc.CallCredentials;
import io.grpc.CallCredentials.RequestInfo; import io.grpc.CallCredentials.RequestInfo;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ChannelLogger; import io.grpc.ChannelLogger;
import io.grpc.ClientStreamTracer;
import io.grpc.IntegerMarshaller; import io.grpc.IntegerMarshaller;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.MethodDescriptor; import io.grpc.MethodDescriptor;
@ -49,6 +50,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.JUnit4; import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoJUnit;
@ -86,6 +88,9 @@ public class CallCredentialsApplyingTest {
@Mock @Mock
private ChannelLogger channelLogger; private ChannelLogger channelLogger;
private static final ClientStreamTracer[] tracers = new ClientStreamTracer[] {
new ClientStreamTracer() {}
};
private static final String AUTHORITY = "testauthority"; private static final String AUTHORITY = "testauthority";
private static final String USER_AGENT = "testuseragent"; private static final String USER_AGENT = "testuseragent";
private static final Attributes.Key<String> ATTR_KEY = Attributes.Key.create("somekey"); private static final Attributes.Key<String> ATTR_KEY = Attributes.Key.create("somekey");
@ -117,7 +122,9 @@ public class CallCredentialsApplyingTest {
origHeaders.put(ORIG_HEADER_KEY, ORIG_HEADER_VALUE); origHeaders.put(ORIG_HEADER_KEY, ORIG_HEADER_VALUE);
when(mockTransportFactory.newClientTransport(address, clientTransportOptions, channelLogger)) when(mockTransportFactory.newClientTransport(address, clientTransportOptions, channelLogger))
.thenReturn(mockTransport); .thenReturn(mockTransport);
when(mockTransport.newStream(same(method), any(Metadata.class), any(CallOptions.class))) when(mockTransport.newStream(
same(method), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream); .thenReturn(mockStream);
ClientTransportFactory transportFactory = new CallCredentialsApplyingTransportFactory( ClientTransportFactory transportFactory = new CallCredentialsApplyingTransportFactory(
mockTransportFactory, null, mockExecutor); mockTransportFactory, null, mockExecutor);
@ -133,7 +140,7 @@ public class CallCredentialsApplyingTest {
Attributes transportAttrs = Attributes.newBuilder().set(ATTR_KEY, ATTR_VALUE).build(); Attributes transportAttrs = Attributes.newBuilder().set(ATTR_KEY, ATTR_VALUE).build();
when(mockTransport.getAttributes()).thenReturn(transportAttrs); when(mockTransport.getAttributes()).thenReturn(transportAttrs);
transport.newStream(method, origHeaders, callOptions); transport.newStream(method, origHeaders, callOptions, tracers);
ArgumentCaptor<RequestInfo> infoCaptor = ArgumentCaptor.forClass(null); ArgumentCaptor<RequestInfo> infoCaptor = ArgumentCaptor.forClass(null);
verify(mockCreds).applyRequestMetadata(infoCaptor.capture(), same(mockExecutor), verify(mockCreds).applyRequestMetadata(infoCaptor.capture(), same(mockExecutor),
@ -154,8 +161,10 @@ public class CallCredentialsApplyingTest {
when(mockTransport.getAttributes()).thenReturn(transportAttrs); when(mockTransport.getAttributes()).thenReturn(transportAttrs);
Executor anotherExecutor = mock(Executor.class); Executor anotherExecutor = mock(Executor.class);
transport.newStream(method, origHeaders, transport.newStream(
callOptions.withAuthority("calloptions-authority").withExecutor(anotherExecutor)); method, origHeaders,
callOptions.withAuthority("calloptions-authority").withExecutor(anotherExecutor),
tracers);
ArgumentCaptor<RequestInfo> infoCaptor = ArgumentCaptor.forClass(null); ArgumentCaptor<RequestInfo> infoCaptor = ArgumentCaptor.forClass(null);
verify(mockCreds).applyRequestMetadata(infoCaptor.capture(), verify(mockCreds).applyRequestMetadata(infoCaptor.capture(),
@ -175,15 +184,17 @@ public class CallCredentialsApplyingTest {
any(RequestInfo.class), same(mockExecutor), any(RequestInfo.class), same(mockExecutor),
any(CallCredentials.MetadataApplier.class)); any(CallCredentials.MetadataApplier.class));
FailingClientStream stream = FailingClientStream stream = (FailingClientStream) transport.newStream(
(FailingClientStream) transport.newStream(method, origHeaders, callOptions); method, origHeaders, callOptions, tracers);
verify(mockTransport, never()).newStream(method, origHeaders, callOptions); verify(mockTransport, never()).newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
assertEquals(Status.Code.UNAUTHENTICATED, stream.getError().getCode()); assertEquals(Status.Code.UNAUTHENTICATED, stream.getError().getCode());
assertSame(ex, stream.getError().getCause()); assertSame(ex, stream.getError().getCause());
transport.shutdown(Status.UNAVAILABLE); transport.shutdown(Status.UNAVAILABLE);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport).shutdown(Status.UNAVAILABLE); verify(mockTransport).shutdown(Status.UNAVAILABLE);
} }
@ -193,14 +204,15 @@ public class CallCredentialsApplyingTest {
when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY); when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY);
callOptions = callOptions.withCallCredentials(new FakeCallCredentials(CREDS_KEY, CREDS_VALUE)); callOptions = callOptions.withCallCredentials(new FakeCallCredentials(CREDS_KEY, CREDS_VALUE));
ClientStream stream = transport.newStream(method, origHeaders, callOptions); ClientStream stream = transport.newStream(
method, origHeaders, callOptions, tracers);
verify(mockTransport).newStream(method, origHeaders, callOptions); verify(mockTransport).newStream(method, origHeaders, callOptions, tracers);
assertSame(mockStream, stream); assertSame(mockStream, stream);
assertEquals(CREDS_VALUE, origHeaders.get(CREDS_KEY)); assertEquals(CREDS_VALUE, origHeaders.get(CREDS_KEY));
assertEquals(ORIG_HEADER_VALUE, origHeaders.get(ORIG_HEADER_KEY)); assertEquals(ORIG_HEADER_VALUE, origHeaders.get(ORIG_HEADER_KEY));
transport.shutdown(Status.UNAVAILABLE); transport.shutdown(Status.UNAVAILABLE);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport).shutdown(Status.UNAVAILABLE); verify(mockTransport).shutdown(Status.UNAVAILABLE);
} }
@ -220,13 +232,15 @@ public class CallCredentialsApplyingTest {
}).when(mockCreds).applyRequestMetadata(any(RequestInfo.class), }).when(mockCreds).applyRequestMetadata(any(RequestInfo.class),
same(mockExecutor), any(CallCredentials.MetadataApplier.class)); same(mockExecutor), any(CallCredentials.MetadataApplier.class));
FailingClientStream stream = FailingClientStream stream = (FailingClientStream) transport.newStream(
(FailingClientStream) transport.newStream(method, origHeaders, callOptions); method, origHeaders, callOptions, tracers);
verify(mockTransport, never()).newStream(method, origHeaders, callOptions); verify(mockTransport, never()).newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
assertSame(error, stream.getError()); assertSame(error, stream.getError());
transport.shutdownNow(Status.UNAVAILABLE); transport.shutdownNow(Status.UNAVAILABLE);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport).shutdownNow(Status.UNAVAILABLE); verify(mockTransport).shutdownNow(Status.UNAVAILABLE);
} }
@ -236,23 +250,26 @@ public class CallCredentialsApplyingTest {
when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY); when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY);
// Will call applyRequestMetadata(), which is no-op. // Will call applyRequestMetadata(), which is no-op.
DelayedStream stream = (DelayedStream) transport.newStream(method, origHeaders, callOptions); DelayedStream stream = (DelayedStream) transport.newStream(
method, origHeaders, callOptions, tracers);
ArgumentCaptor<CallCredentials.MetadataApplier> applierCaptor = ArgumentCaptor.forClass(null); ArgumentCaptor<CallCredentials.MetadataApplier> applierCaptor = ArgumentCaptor.forClass(null);
verify(mockCreds).applyRequestMetadata(any(RequestInfo.class), verify(mockCreds).applyRequestMetadata(any(RequestInfo.class),
same(mockExecutor), applierCaptor.capture()); same(mockExecutor), applierCaptor.capture());
verify(mockTransport, never()).newStream(method, origHeaders, callOptions); verify(mockTransport, never()).newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
transport.shutdown(Status.UNAVAILABLE); transport.shutdown(Status.UNAVAILABLE);
verify(mockTransport, never()).shutdown(Status.UNAVAILABLE); verify(mockTransport, never()).shutdown(Status.UNAVAILABLE);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
Metadata headers = new Metadata(); Metadata headers = new Metadata();
headers.put(CREDS_KEY, CREDS_VALUE); headers.put(CREDS_KEY, CREDS_VALUE);
applierCaptor.getValue().apply(headers); applierCaptor.getValue().apply(headers);
verify(mockTransport).newStream(method, origHeaders, callOptions); verify(mockTransport).newStream(method, origHeaders, callOptions, tracers);
assertSame(mockStream, stream.getRealStream()); assertSame(mockStream, stream.getRealStream());
assertEquals(CREDS_VALUE, origHeaders.get(CREDS_KEY)); assertEquals(CREDS_VALUE, origHeaders.get(CREDS_KEY));
assertEquals(ORIG_HEADER_VALUE, origHeaders.get(ORIG_HEADER_KEY)); assertEquals(ORIG_HEADER_VALUE, origHeaders.get(ORIG_HEADER_KEY));
@ -261,20 +278,20 @@ public class CallCredentialsApplyingTest {
@Test @Test
public void delayedShutdown_shutdownShutdownNowThenApply() { public void delayedShutdown_shutdownShutdownNowThenApply() {
transport.newStream(method, origHeaders, callOptions); transport.newStream(method, origHeaders, callOptions, tracers);
ArgumentCaptor<CallCredentials.MetadataApplier> applierCaptor = ArgumentCaptor.forClass(null); ArgumentCaptor<CallCredentials.MetadataApplier> applierCaptor = ArgumentCaptor.forClass(null);
verify(mockCreds).applyRequestMetadata(any(RequestInfo.class), verify(mockCreds).applyRequestMetadata(any(RequestInfo.class),
same(mockExecutor), applierCaptor.capture()); same(mockExecutor), applierCaptor.capture());
transport.shutdown(Status.UNAVAILABLE); transport.shutdown(Status.UNAVAILABLE);
transport.shutdownNow(Status.ABORTED); transport.shutdownNow(Status.ABORTED);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport, never()).shutdown(any(Status.class)); verify(mockTransport, never()).shutdown(any(Status.class));
verify(mockTransport, never()).shutdownNow(any(Status.class)); verify(mockTransport, never()).shutdownNow(any(Status.class));
Metadata headers = new Metadata(); Metadata headers = new Metadata();
headers.put(CREDS_KEY, CREDS_VALUE); headers.put(CREDS_KEY, CREDS_VALUE);
applierCaptor.getValue().apply(headers); applierCaptor.getValue().apply(headers);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport).shutdown(Status.UNAVAILABLE); verify(mockTransport).shutdown(Status.UNAVAILABLE);
verify(mockTransport).shutdownNow(Status.ABORTED); verify(mockTransport).shutdownNow(Status.ABORTED);
@ -282,12 +299,12 @@ public class CallCredentialsApplyingTest {
@Test @Test
public void delayedShutdown_shutdownThenApplyThenShutdownNow() { public void delayedShutdown_shutdownThenApplyThenShutdownNow() {
transport.newStream(method, origHeaders, callOptions); transport.newStream(method, origHeaders, callOptions, tracers);
ArgumentCaptor<CallCredentials.MetadataApplier> applierCaptor = ArgumentCaptor.forClass(null); ArgumentCaptor<CallCredentials.MetadataApplier> applierCaptor = ArgumentCaptor.forClass(null);
verify(mockCreds).applyRequestMetadata(any(RequestInfo.class), verify(mockCreds).applyRequestMetadata(any(RequestInfo.class),
same(mockExecutor), applierCaptor.capture()); same(mockExecutor), applierCaptor.capture());
transport.shutdown(Status.UNAVAILABLE); transport.shutdown(Status.UNAVAILABLE);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport, never()).shutdown(any(Status.class)); verify(mockTransport, never()).shutdown(any(Status.class));
Metadata headers = new Metadata(); Metadata headers = new Metadata();
@ -308,25 +325,25 @@ public class CallCredentialsApplyingTest {
Metadata headers = new Metadata(); Metadata headers = new Metadata();
headers.put(CREDS_KEY, CREDS_VALUE); headers.put(CREDS_KEY, CREDS_VALUE);
transport.newStream(method, origHeaders, callOptions); transport.newStream(method, origHeaders, callOptions, tracers);
transport.newStream(method, origHeaders, callOptions); transport.newStream(method, origHeaders, callOptions, tracers);
transport.newStream(method, origHeaders, callOptions); transport.newStream(method, origHeaders, callOptions, tracers);
ArgumentCaptor<CallCredentials.MetadataApplier> applierCaptor = ArgumentCaptor.forClass(null); ArgumentCaptor<CallCredentials.MetadataApplier> applierCaptor = ArgumentCaptor.forClass(null);
verify(mockCreds, times(3)).applyRequestMetadata(any(RequestInfo.class), verify(mockCreds, times(3)).applyRequestMetadata(any(RequestInfo.class),
same(mockExecutor), applierCaptor.capture()); same(mockExecutor), applierCaptor.capture());
applierCaptor.getAllValues().get(1).apply(headers); applierCaptor.getAllValues().get(1).apply(headers);
transport.shutdown(Status.UNAVAILABLE); transport.shutdown(Status.UNAVAILABLE);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport, never()).shutdown(Status.UNAVAILABLE); verify(mockTransport, never()).shutdown(Status.UNAVAILABLE);
applierCaptor.getAllValues().get(0).apply(headers); applierCaptor.getAllValues().get(0).apply(headers);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport, never()).shutdown(Status.UNAVAILABLE); verify(mockTransport, never()).shutdown(Status.UNAVAILABLE);
applierCaptor.getAllValues().get(2).apply(headers); applierCaptor.getAllValues().get(2).apply(headers);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport).shutdown(Status.UNAVAILABLE); verify(mockTransport).shutdown(Status.UNAVAILABLE);
} }
@ -336,7 +353,8 @@ public class CallCredentialsApplyingTest {
when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY); when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY);
// Will call applyRequestMetadata(), which is no-op. // Will call applyRequestMetadata(), which is no-op.
DelayedStream stream = (DelayedStream) transport.newStream(method, origHeaders, callOptions); DelayedStream stream = (DelayedStream) transport.newStream(
method, origHeaders, callOptions, tracers);
ArgumentCaptor<CallCredentials.MetadataApplier> applierCaptor = ArgumentCaptor.forClass(null); ArgumentCaptor<CallCredentials.MetadataApplier> applierCaptor = ArgumentCaptor.forClass(null);
verify(mockCreds).applyRequestMetadata(any(RequestInfo.class), verify(mockCreds).applyRequestMetadata(any(RequestInfo.class),
@ -345,11 +363,13 @@ public class CallCredentialsApplyingTest {
Status error = Status.FAILED_PRECONDITION.withDescription("channel not secure for creds"); Status error = Status.FAILED_PRECONDITION.withDescription("channel not secure for creds");
applierCaptor.getValue().fail(error); applierCaptor.getValue().fail(error);
verify(mockTransport, never()).newStream(method, origHeaders, callOptions); verify(mockTransport, never()).newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
FailingClientStream failingStream = (FailingClientStream) stream.getRealStream(); FailingClientStream failingStream = (FailingClientStream) stream.getRealStream();
assertSame(error, failingStream.getError()); assertSame(error, failingStream.getError());
transport.shutdown(Status.UNAVAILABLE); transport.shutdown(Status.UNAVAILABLE);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport).shutdown(Status.UNAVAILABLE); verify(mockTransport).shutdown(Status.UNAVAILABLE);
} }
@ -357,14 +377,15 @@ public class CallCredentialsApplyingTest {
@Test @Test
public void noCreds() { public void noCreds() {
callOptions = callOptions.withCallCredentials(null); callOptions = callOptions.withCallCredentials(null);
ClientStream stream = transport.newStream(method, origHeaders, callOptions); ClientStream stream = transport.newStream(
method, origHeaders, callOptions, tracers);
verify(mockTransport).newStream(method, origHeaders, callOptions); verify(mockTransport).newStream(method, origHeaders, callOptions, tracers);
assertSame(mockStream, stream); assertSame(mockStream, stream);
assertNull(origHeaders.get(CREDS_KEY)); assertNull(origHeaders.get(CREDS_KEY));
assertEquals(ORIG_HEADER_VALUE, origHeaders.get(ORIG_HEADER_KEY)); assertEquals(ORIG_HEADER_VALUE, origHeaders.get(ORIG_HEADER_KEY));
transport.shutdown(Status.UNAVAILABLE); transport.shutdown(Status.UNAVAILABLE);
assertTrue(transport.newStream(method, origHeaders, callOptions) assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
instanceof FailingClientStream); instanceof FailingClientStream);
verify(mockTransport).shutdown(Status.UNAVAILABLE); verify(mockTransport).shutdown(Status.UNAVAILABLE);
} }
@ -373,7 +394,8 @@ public class CallCredentialsApplyingTest {
public void justCallOptionCreds() { public void justCallOptionCreds() {
callOptions = callOptions.withCallCredentials(new FakeCallCredentials(CREDS_KEY, CREDS_VALUE)); callOptions = callOptions.withCallCredentials(new FakeCallCredentials(CREDS_KEY, CREDS_VALUE));
ClientStream stream = transport.newStream(method, origHeaders, callOptions); ClientStream stream = transport.newStream(
method, origHeaders, callOptions, tracers);
assertSame(mockStream, stream); assertSame(mockStream, stream);
assertEquals(CREDS_VALUE, origHeaders.get(CREDS_KEY)); assertEquals(CREDS_VALUE, origHeaders.get(CREDS_KEY));
@ -388,7 +410,8 @@ public class CallCredentialsApplyingTest {
transportFactory.newClientTransport(address, clientTransportOptions, channelLogger); transportFactory.newClientTransport(address, clientTransportOptions, channelLogger);
callOptions = callOptions.withCallCredentials(null); callOptions = callOptions.withCallCredentials(null);
ClientStream stream = transport.newStream(method, origHeaders, callOptions); ClientStream stream = transport.newStream(
method, origHeaders, callOptions, tracers);
assertSame(mockStream, stream); assertSame(mockStream, stream);
assertEquals(CREDS_VALUE, origHeaders.get(CREDS_KEY)); assertEquals(CREDS_VALUE, origHeaders.get(CREDS_KEY));
@ -406,7 +429,8 @@ public class CallCredentialsApplyingTest {
String creds2Value = "some more credentials"; String creds2Value = "some more credentials";
callOptions = callOptions.withCallCredentials(new FakeCallCredentials(creds2Key, creds2Value)); callOptions = callOptions.withCallCredentials(new FakeCallCredentials(creds2Key, creds2Value));
ClientStream stream = transport.newStream(method, origHeaders, callOptions); ClientStream stream = transport.newStream(
method, origHeaders, callOptions, tracers);
assertSame(mockStream, stream); assertSame(mockStream, stream);
assertEquals(CREDS_VALUE, origHeaders.get(CREDS_KEY)); assertEquals(CREDS_VALUE, origHeaders.get(CREDS_KEY));

View File

@ -37,6 +37,7 @@ import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
@ -47,6 +48,7 @@ import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientCall; import io.grpc.ClientCall;
import io.grpc.ClientStreamTracer; import io.grpc.ClientStreamTracer;
import io.grpc.ClientStreamTracer.StreamInfo;
import io.grpc.Codec; import io.grpc.Codec;
import io.grpc.Context; import io.grpc.Context;
import io.grpc.Deadline; import io.grpc.Deadline;
@ -143,6 +145,8 @@ public class ClientCallImplTest {
any(Metadata.class), any(Metadata.class),
any(Context.class))) any(Context.class)))
.thenReturn(stream); .thenReturn(stream);
when(streamTracerFactory.newClientStreamTracer(any(StreamInfo.class), any(Metadata.class)))
.thenReturn(new ClientStreamTracer() {});
doAnswer(new Answer<Void>() { doAnswer(new Answer<Void>() {
@Override @Override
public Void answer(InvocationOnMock in) { public Void answer(InvocationOnMock in) {
@ -156,7 +160,7 @@ public class ClientCallImplTest {
@After @After
public void tearDown() { public void tearDown() {
verifyNoInteractions(streamTracerFactory); verifyNoMoreInteractions(streamTracerFactory);
} }
@Test @Test
@ -763,6 +767,7 @@ public class ClientCallImplTest {
channelCallTracer, configSelector) channelCallTracer, configSelector)
.setDecompressorRegistry(decompressorRegistry); .setDecompressorRegistry(decompressorRegistry);
call.start(callListener, new Metadata()); call.start(callListener, new Metadata());
verify(streamTracerFactory).newClientStreamTracer(any(StreamInfo.class), any(Metadata.class));
verify(clientStreamProvider, never()) verify(clientStreamProvider, never())
.newStream( .newStream(
(MethodDescriptor<?, ?>) any(MethodDescriptor.class), (MethodDescriptor<?, ?>) any(MethodDescriptor.class),

View File

@ -36,6 +36,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer;
import io.grpc.IntegerMarshaller; import io.grpc.IntegerMarshaller;
import io.grpc.LoadBalancer.PickResult; import io.grpc.LoadBalancer.PickResult;
import io.grpc.LoadBalancer.PickSubchannelArgs; import io.grpc.LoadBalancer.PickSubchannelArgs;
@ -57,6 +58,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.JUnit4; import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Captor; import org.mockito.Captor;
import org.mockito.InOrder; import org.mockito.InOrder;
import org.mockito.Mock; import org.mockito.Mock;
@ -89,6 +91,9 @@ public class DelayedClientTransportTest {
= CallOptions.Key.createWithDefault("shard-id", -1); = CallOptions.Key.createWithDefault("shard-id", -1);
private static final Status SHUTDOWN_STATUS = private static final Status SHUTDOWN_STATUS =
Status.UNAVAILABLE.withDescription("shutdown called"); Status.UNAVAILABLE.withDescription("shutdown called");
private static final ClientStreamTracer[] tracers = new ClientStreamTracer[] {
new ClientStreamTracer() {}
};
private final MethodDescriptor<String, Integer> method = private final MethodDescriptor<String, Integer> method =
MethodDescriptor.<String, Integer>newBuilder() MethodDescriptor.<String, Integer>newBuilder()
@ -122,9 +127,13 @@ public class DelayedClientTransportTest {
.thenReturn(PickResult.withSubchannel(mockSubchannel)); .thenReturn(PickResult.withSubchannel(mockSubchannel));
when(mockSubchannel.getInternalSubchannel()).thenReturn(mockInternalSubchannel); when(mockSubchannel.getInternalSubchannel()).thenReturn(mockInternalSubchannel);
when(mockInternalSubchannel.obtainActiveTransport()).thenReturn(mockRealTransport); when(mockInternalSubchannel.obtainActiveTransport()).thenReturn(mockRealTransport);
when(mockRealTransport.newStream(same(method), same(headers), same(callOptions))) when(mockRealTransport.newStream(
same(method), same(headers), same(callOptions),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockRealStream); .thenReturn(mockRealStream);
when(mockRealTransport2.newStream(same(method2), same(headers2), same(callOptions2))) when(mockRealTransport2.newStream(
same(method2), same(headers2), same(callOptions2),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockRealStream2); .thenReturn(mockRealStream2);
delayedTransport.start(transportListener); delayedTransport.start(transportListener);
} }
@ -135,7 +144,8 @@ public class DelayedClientTransportTest {
@Test public void streamStartThenAssignTransport() { @Test public void streamStartThenAssignTransport() {
assertFalse(delayedTransport.hasPendingStreams()); assertFalse(delayedTransport.hasPendingStreams());
ClientStream stream = delayedTransport.newStream(method, headers, callOptions); ClientStream stream = delayedTransport.newStream(
method, headers, callOptions, tracers);
stream.start(streamListener); stream.start(streamListener);
assertEquals(1, delayedTransport.getPendingStreamsCount()); assertEquals(1, delayedTransport.getPendingStreamsCount());
assertTrue(delayedTransport.hasPendingStreams()); assertTrue(delayedTransport.hasPendingStreams());
@ -145,7 +155,9 @@ public class DelayedClientTransportTest {
assertEquals(0, delayedTransport.getPendingStreamsCount()); assertEquals(0, delayedTransport.getPendingStreamsCount());
assertFalse(delayedTransport.hasPendingStreams()); assertFalse(delayedTransport.hasPendingStreams());
assertEquals(1, fakeExecutor.runDueTasks()); assertEquals(1, fakeExecutor.runDueTasks());
verify(mockRealTransport).newStream(same(method), same(headers), same(callOptions)); verify(mockRealTransport).newStream(
same(method), same(headers), same(callOptions),
ArgumentMatchers.<ClientStreamTracer[]>any());
verify(mockRealStream).start(listenerCaptor.capture()); verify(mockRealStream).start(listenerCaptor.capture());
verifyNoMoreInteractions(streamListener); verifyNoMoreInteractions(streamListener);
listenerCaptor.getValue().onReady(); listenerCaptor.getValue().onReady();
@ -154,7 +166,7 @@ public class DelayedClientTransportTest {
} }
@Test public void newStreamThenAssignTransportThenShutdown() { @Test public void newStreamThenAssignTransportThenShutdown() {
ClientStream stream = delayedTransport.newStream(method, headers, callOptions); ClientStream stream = delayedTransport.newStream(method, headers, callOptions, tracers);
assertEquals(1, delayedTransport.getPendingStreamsCount()); assertEquals(1, delayedTransport.getPendingStreamsCount());
assertTrue(stream instanceof DelayedStream); assertTrue(stream instanceof DelayedStream);
delayedTransport.reprocess(mockPicker); delayedTransport.reprocess(mockPicker);
@ -163,7 +175,9 @@ public class DelayedClientTransportTest {
verify(transportListener).transportShutdown(same(SHUTDOWN_STATUS)); verify(transportListener).transportShutdown(same(SHUTDOWN_STATUS));
verify(transportListener).transportTerminated(); verify(transportListener).transportTerminated();
assertEquals(0, fakeExecutor.runDueTasks()); assertEquals(0, fakeExecutor.runDueTasks());
verify(mockRealTransport).newStream(same(method), same(headers), same(callOptions)); verify(mockRealTransport).newStream(
same(method), same(headers), same(callOptions),
ArgumentMatchers.<ClientStreamTracer[]>any());
stream.start(streamListener); stream.start(streamListener);
verify(mockRealStream).start(same(streamListener)); verify(mockRealStream).start(same(streamListener));
} }
@ -181,11 +195,13 @@ public class DelayedClientTransportTest {
delayedTransport.shutdown(SHUTDOWN_STATUS); delayedTransport.shutdown(SHUTDOWN_STATUS);
verify(transportListener).transportShutdown(same(SHUTDOWN_STATUS)); verify(transportListener).transportShutdown(same(SHUTDOWN_STATUS));
verify(transportListener).transportTerminated(); verify(transportListener).transportTerminated();
ClientStream stream = delayedTransport.newStream(method, headers, callOptions); ClientStream stream = delayedTransport.newStream(
method, headers, callOptions, tracers);
assertEquals(0, delayedTransport.getPendingStreamsCount()); assertEquals(0, delayedTransport.getPendingStreamsCount());
assertTrue(stream instanceof FailingClientStream); assertTrue(stream instanceof FailingClientStream);
verify(mockRealTransport, never()).newStream( verify(mockRealTransport, never()).newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class)); any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
} }
@Test public void assignTransportThenShutdownNowThenNewStream() { @Test public void assignTransportThenShutdownNowThenNewStream() {
@ -193,15 +209,18 @@ public class DelayedClientTransportTest {
delayedTransport.shutdownNow(Status.UNAVAILABLE); delayedTransport.shutdownNow(Status.UNAVAILABLE);
verify(transportListener).transportShutdown(any(Status.class)); verify(transportListener).transportShutdown(any(Status.class));
verify(transportListener).transportTerminated(); verify(transportListener).transportTerminated();
ClientStream stream = delayedTransport.newStream(method, headers, callOptions); ClientStream stream = delayedTransport.newStream(
method, headers, callOptions, tracers);
assertEquals(0, delayedTransport.getPendingStreamsCount()); assertEquals(0, delayedTransport.getPendingStreamsCount());
assertTrue(stream instanceof FailingClientStream); assertTrue(stream instanceof FailingClientStream);
verify(mockRealTransport, never()).newStream( verify(mockRealTransport, never()).newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class)); any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
} }
@Test public void startThenCancelStreamWithoutSetTransport() { @Test public void startThenCancelStreamWithoutSetTransport() {
ClientStream stream = delayedTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); ClientStream stream = delayedTransport.newStream(
method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(streamListener); stream.start(streamListener);
assertEquals(1, delayedTransport.getPendingStreamsCount()); assertEquals(1, delayedTransport.getPendingStreamsCount());
stream.cancel(Status.CANCELLED); stream.cancel(Status.CANCELLED);
@ -213,7 +232,8 @@ public class DelayedClientTransportTest {
} }
@Test public void newStreamThenShutdownTransportThenAssignTransport() { @Test public void newStreamThenShutdownTransportThenAssignTransport() {
ClientStream stream = delayedTransport.newStream(method, headers, callOptions); ClientStream stream = delayedTransport.newStream(
method, headers, callOptions, tracers);
stream.start(streamListener); stream.start(streamListener);
delayedTransport.shutdown(SHUTDOWN_STATUS); delayedTransport.shutdown(SHUTDOWN_STATUS);
@ -225,7 +245,8 @@ public class DelayedClientTransportTest {
// ... and will proceed if a real transport is available // ... and will proceed if a real transport is available
delayedTransport.reprocess(mockPicker); delayedTransport.reprocess(mockPicker);
fakeExecutor.runDueTasks(); fakeExecutor.runDueTasks();
verify(mockRealTransport).newStream(method, headers, callOptions); verify(mockRealTransport).newStream(
method, headers, callOptions, tracers);
verify(mockRealStream).start(any(ClientStreamListener.class)); verify(mockRealStream).start(any(ClientStreamListener.class));
// Since no more streams are pending, delayed transport is now terminated // Since no more streams are pending, delayed transport is now terminated
@ -233,7 +254,8 @@ public class DelayedClientTransportTest {
verify(transportListener).transportTerminated(); verify(transportListener).transportTerminated();
// Further newStream() will return a failing stream // Further newStream() will return a failing stream
stream = delayedTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); stream = delayedTransport.newStream(
method, new Metadata(), CallOptions.DEFAULT, tracers);
verify(streamListener, never()).closed( verify(streamListener, never()).closed(
any(Status.class), any(RpcProgress.class), any(Metadata.class)); any(Status.class), any(RpcProgress.class), any(Metadata.class));
stream.start(streamListener); stream.start(streamListener);
@ -247,7 +269,8 @@ public class DelayedClientTransportTest {
} }
@Test public void newStreamThenShutdownTransportThenCancelStream() { @Test public void newStreamThenShutdownTransportThenCancelStream() {
ClientStream stream = delayedTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); ClientStream stream = delayedTransport.newStream(
method, new Metadata(), CallOptions.DEFAULT, tracers);
delayedTransport.shutdown(SHUTDOWN_STATUS); delayedTransport.shutdown(SHUTDOWN_STATUS);
verify(transportListener).transportShutdown(same(SHUTDOWN_STATUS)); verify(transportListener).transportShutdown(same(SHUTDOWN_STATUS));
verify(transportListener, times(0)).transportTerminated(); verify(transportListener, times(0)).transportTerminated();
@ -264,7 +287,8 @@ public class DelayedClientTransportTest {
delayedTransport.shutdown(SHUTDOWN_STATUS); delayedTransport.shutdown(SHUTDOWN_STATUS);
verify(transportListener).transportShutdown(same(SHUTDOWN_STATUS)); verify(transportListener).transportShutdown(same(SHUTDOWN_STATUS));
verify(transportListener).transportTerminated(); verify(transportListener).transportTerminated();
ClientStream stream = delayedTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); ClientStream stream = delayedTransport.newStream(
method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(streamListener); stream.start(streamListener);
verify(streamListener).closed( verify(streamListener).closed(
statusCaptor.capture(), any(RpcProgress.class), any(Metadata.class)); statusCaptor.capture(), any(RpcProgress.class), any(Metadata.class));
@ -272,7 +296,8 @@ public class DelayedClientTransportTest {
} }
@Test public void startStreamThenShutdownNow() { @Test public void startStreamThenShutdownNow() {
ClientStream stream = delayedTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); ClientStream stream = delayedTransport.newStream(
method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(streamListener); stream.start(streamListener);
delayedTransport.shutdownNow(Status.UNAVAILABLE); delayedTransport.shutdownNow(Status.UNAVAILABLE);
verify(transportListener).transportShutdown(any(Status.class)); verify(transportListener).transportShutdown(any(Status.class));
@ -286,7 +311,8 @@ public class DelayedClientTransportTest {
delayedTransport.shutdownNow(Status.UNAVAILABLE); delayedTransport.shutdownNow(Status.UNAVAILABLE);
verify(transportListener).transportShutdown(any(Status.class)); verify(transportListener).transportShutdown(any(Status.class));
verify(transportListener).transportTerminated(); verify(transportListener).transportTerminated();
ClientStream stream = delayedTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); ClientStream stream = delayedTransport.newStream(
method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(streamListener); stream.start(streamListener);
verify(streamListener).closed( verify(streamListener).closed(
statusCaptor.capture(), any(RpcProgress.class), any(Metadata.class)); statusCaptor.capture(), any(RpcProgress.class), any(Metadata.class));
@ -301,55 +327,59 @@ public class DelayedClientTransportTest {
AbstractSubchannel subchannel1 = mock(AbstractSubchannel.class); AbstractSubchannel subchannel1 = mock(AbstractSubchannel.class);
AbstractSubchannel subchannel2 = mock(AbstractSubchannel.class); AbstractSubchannel subchannel2 = mock(AbstractSubchannel.class);
AbstractSubchannel subchannel3 = mock(AbstractSubchannel.class); AbstractSubchannel subchannel3 = mock(AbstractSubchannel.class);
when(mockRealTransport.newStream(any(MethodDescriptor.class), any(Metadata.class), when(mockRealTransport.newStream(
any(CallOptions.class))).thenReturn(mockRealStream); any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
when(mockRealTransport2.newStream(any(MethodDescriptor.class), any(Metadata.class), ArgumentMatchers.<ClientStreamTracer[]>any()))
any(CallOptions.class))).thenReturn(mockRealStream2); .thenReturn(mockRealStream);
when(mockRealTransport2.newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockRealStream2);
when(subchannel1.getInternalSubchannel()).thenReturn(newTransportProvider(mockRealTransport)); when(subchannel1.getInternalSubchannel()).thenReturn(newTransportProvider(mockRealTransport));
when(subchannel2.getInternalSubchannel()).thenReturn(newTransportProvider(mockRealTransport2)); when(subchannel2.getInternalSubchannel()).thenReturn(newTransportProvider(mockRealTransport2));
when(subchannel3.getInternalSubchannel()).thenReturn(newTransportProvider(null)); when(subchannel3.getInternalSubchannel()).thenReturn(newTransportProvider(null));
// Fail-fast streams // Fail-fast streams
DelayedStream ff1 = (DelayedStream) delayedTransport.newStream( DelayedStream ff1 = (DelayedStream) delayedTransport.newStream(
method, headers, failFastCallOptions); method, headers, failFastCallOptions, tracers);
ff1.start(mock(ClientStreamListener.class)); ff1.start(mock(ClientStreamListener.class));
ff1.halfClose(); ff1.halfClose();
PickSubchannelArgsImpl ff1args = new PickSubchannelArgsImpl(method, headers, PickSubchannelArgsImpl ff1args = new PickSubchannelArgsImpl(method, headers,
failFastCallOptions); failFastCallOptions);
verify(transportListener).transportInUse(true); verify(transportListener).transportInUse(true);
DelayedStream ff2 = (DelayedStream) delayedTransport.newStream( DelayedStream ff2 = (DelayedStream) delayedTransport.newStream(
method2, headers2, failFastCallOptions); method2, headers2, failFastCallOptions, tracers);
PickSubchannelArgsImpl ff2args = new PickSubchannelArgsImpl(method2, headers2, PickSubchannelArgsImpl ff2args = new PickSubchannelArgsImpl(method2, headers2,
failFastCallOptions); failFastCallOptions);
DelayedStream ff3 = (DelayedStream) delayedTransport.newStream( DelayedStream ff3 = (DelayedStream) delayedTransport.newStream(
method, headers, failFastCallOptions); method, headers, failFastCallOptions, tracers);
PickSubchannelArgsImpl ff3args = new PickSubchannelArgsImpl(method, headers, PickSubchannelArgsImpl ff3args = new PickSubchannelArgsImpl(method, headers,
failFastCallOptions); failFastCallOptions);
DelayedStream ff4 = (DelayedStream) delayedTransport.newStream( DelayedStream ff4 = (DelayedStream) delayedTransport.newStream(
method2, headers2, failFastCallOptions); method2, headers2, failFastCallOptions, tracers);
PickSubchannelArgsImpl ff4args = new PickSubchannelArgsImpl(method2, headers2, PickSubchannelArgsImpl ff4args = new PickSubchannelArgsImpl(method2, headers2,
failFastCallOptions); failFastCallOptions);
// Wait-for-ready streams // Wait-for-ready streams
FakeClock wfr3Executor = new FakeClock(); FakeClock wfr3Executor = new FakeClock();
DelayedStream wfr1 = (DelayedStream) delayedTransport.newStream( DelayedStream wfr1 = (DelayedStream) delayedTransport.newStream(
method, headers, waitForReadyCallOptions); method, headers, waitForReadyCallOptions, tracers);
PickSubchannelArgsImpl wfr1args = new PickSubchannelArgsImpl(method, headers, PickSubchannelArgsImpl wfr1args = new PickSubchannelArgsImpl(method, headers,
waitForReadyCallOptions); waitForReadyCallOptions);
DelayedStream wfr2 = (DelayedStream) delayedTransport.newStream( DelayedStream wfr2 = (DelayedStream) delayedTransport.newStream(
method2, headers2, waitForReadyCallOptions); method2, headers2, waitForReadyCallOptions, tracers);
PickSubchannelArgsImpl wfr2args = new PickSubchannelArgsImpl(method2, headers2, PickSubchannelArgsImpl wfr2args = new PickSubchannelArgsImpl(method2, headers2,
waitForReadyCallOptions); waitForReadyCallOptions);
CallOptions wfr3callOptions = waitForReadyCallOptions.withExecutor( CallOptions wfr3callOptions = waitForReadyCallOptions.withExecutor(
wfr3Executor.getScheduledExecutorService()); wfr3Executor.getScheduledExecutorService());
DelayedStream wfr3 = (DelayedStream) delayedTransport.newStream( DelayedStream wfr3 = (DelayedStream) delayedTransport.newStream(
method, headers, wfr3callOptions); method, headers, wfr3callOptions, tracers);
wfr3.start(mock(ClientStreamListener.class)); wfr3.start(mock(ClientStreamListener.class));
wfr3.halfClose(); wfr3.halfClose();
PickSubchannelArgsImpl wfr3args = new PickSubchannelArgsImpl(method, headers, PickSubchannelArgsImpl wfr3args = new PickSubchannelArgsImpl(method, headers,
wfr3callOptions); wfr3callOptions);
DelayedStream wfr4 = (DelayedStream) delayedTransport.newStream( DelayedStream wfr4 = (DelayedStream) delayedTransport.newStream(
method2, headers2, waitForReadyCallOptions); method2, headers2, waitForReadyCallOptions, tracers);
PickSubchannelArgsImpl wfr4args = new PickSubchannelArgsImpl(method2, headers2, PickSubchannelArgsImpl wfr4args = new PickSubchannelArgsImpl(method2, headers2,
waitForReadyCallOptions); waitForReadyCallOptions);
@ -386,8 +416,10 @@ public class DelayedClientTransportTest {
// streams are now owned by a real transport (which should prevent the Channel from // streams are now owned by a real transport (which should prevent the Channel from
// terminating). // terminating).
// ff1 and wfr1 went through // ff1 and wfr1 went through
verify(mockRealTransport).newStream(method, headers, failFastCallOptions); verify(mockRealTransport).newStream(
verify(mockRealTransport2).newStream(method, headers, waitForReadyCallOptions); method, headers, failFastCallOptions, tracers);
verify(mockRealTransport2).newStream(
method, headers, waitForReadyCallOptions, tracers);
assertSame(mockRealStream, ff1.getRealStream()); assertSame(mockRealStream, ff1.getRealStream());
assertSame(mockRealStream2, wfr1.getRealStream()); assertSame(mockRealStream2, wfr1.getRealStream());
verify(mockRealStream).start(any(ClientStreamListener.class)); verify(mockRealStream).start(any(ClientStreamListener.class));
@ -443,7 +475,7 @@ public class DelayedClientTransportTest {
// New streams will use the last picker // New streams will use the last picker
DelayedStream wfr5 = (DelayedStream) delayedTransport.newStream( DelayedStream wfr5 = (DelayedStream) delayedTransport.newStream(
method, headers, waitForReadyCallOptions); method, headers, waitForReadyCallOptions, tracers);
assertNull(wfr5.getRealStream()); assertNull(wfr5.getRealStream());
inOrder.verify(picker).pickSubchannel( inOrder.verify(picker).pickSubchannel(
new PickSubchannelArgsImpl(method, headers, waitForReadyCallOptions)); new PickSubchannelArgsImpl(method, headers, waitForReadyCallOptions));
@ -474,14 +506,17 @@ public class DelayedClientTransportTest {
when(subchannel.getInternalSubchannel()).thenReturn(mockInternalSubchannel); when(subchannel.getInternalSubchannel()).thenReturn(mockInternalSubchannel);
when(picker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn( when(picker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn(
PickResult.withSubchannel(subchannel)); PickResult.withSubchannel(subchannel));
when(mockRealTransport.newStream(any(MethodDescriptor.class), any(Metadata.class), when(mockRealTransport.newStream(
any(CallOptions.class))).thenReturn(mockRealStream); any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockRealStream);
delayedTransport.reprocess(picker); delayedTransport.reprocess(picker);
verifyNoMoreInteractions(picker); verifyNoMoreInteractions(picker);
verifyNoMoreInteractions(transportListener); verifyNoMoreInteractions(transportListener);
// Though picker was not originally used, it will be saved and serve future streams. // Though picker was not originally used, it will be saved and serve future streams.
ClientStream stream = delayedTransport.newStream(method, headers, CallOptions.DEFAULT); ClientStream stream = delayedTransport.newStream(
method, headers, CallOptions.DEFAULT, tracers);
verify(picker).pickSubchannel(new PickSubchannelArgsImpl(method, headers, CallOptions.DEFAULT)); verify(picker).pickSubchannel(new PickSubchannelArgsImpl(method, headers, CallOptions.DEFAULT));
verify(mockInternalSubchannel).obtainActiveTransport(); verify(mockInternalSubchannel).obtainActiveTransport();
assertSame(mockRealStream, stream); assertSame(mockRealStream, stream);
@ -519,7 +554,7 @@ public class DelayedClientTransportTest {
@Override @Override
public void run() { public void run() {
// Will call pickSubchannel and wait on barrier // Will call pickSubchannel and wait on barrier
delayedTransport.newStream(method, headers, callOptions); delayedTransport.newStream(method, headers, callOptions, tracers);
} }
}; };
sideThread.start(); sideThread.start();
@ -552,7 +587,7 @@ public class DelayedClientTransportTest {
@Override @Override
public void run() { public void run() {
// Will call pickSubchannel and wait on barrier // Will call pickSubchannel and wait on barrier
delayedTransport.newStream(method, headers2, callOptions); delayedTransport.newStream(method, headers2, callOptions, tracers);
} }
}; };
sideThread2.start(); sideThread2.start();
@ -600,7 +635,8 @@ public class DelayedClientTransportTest {
// Because there is no pending stream yet, it will do nothing but save the picker. // Because there is no pending stream yet, it will do nothing but save the picker.
delayedTransport.reprocess(picker); delayedTransport.reprocess(picker);
ClientStream stream = delayedTransport.newStream(method, headers, callOptions); ClientStream stream = delayedTransport.newStream(
method, headers, callOptions, tracers);
stream.start(streamListener); stream.start(streamListener);
assertTrue(delayedTransport.hasPendingStreams()); assertTrue(delayedTransport.hasPendingStreams());
verify(transportListener).transportInUse(true); verify(transportListener).transportInUse(true);
@ -609,7 +645,7 @@ public class DelayedClientTransportTest {
@Test @Test
public void pendingStream_appendTimeoutInsight_waitForReady() { public void pendingStream_appendTimeoutInsight_waitForReady() {
ClientStream stream = delayedTransport.newStream( ClientStream stream = delayedTransport.newStream(
method, headers, callOptions.withWaitForReady()); method, headers, callOptions.withWaitForReady(), tracers);
stream.start(streamListener); stream.start(streamListener);
InsightBuilder insight = new InsightBuilder(); InsightBuilder insight = new InsightBuilder();
stream.appendTimeoutInsight(insight); stream.appendTimeoutInsight(insight);

View File

@ -21,6 +21,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import io.grpc.ClientStreamTracer;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.Status; import io.grpc.Status;
import io.grpc.internal.ClientStreamListener.RpcProgress; import io.grpc.internal.ClientStreamListener.RpcProgress;
@ -33,13 +34,16 @@ import org.junit.runners.JUnit4;
*/ */
@RunWith(JUnit4.class) @RunWith(JUnit4.class)
public class FailingClientStreamTest { public class FailingClientStreamTest {
private static final ClientStreamTracer[] tracers = new ClientStreamTracer[] {
new ClientStreamTracer() {}
};
@Test @Test
public void processedRpcProgressPopulatedToListener() { public void processedRpcProgressPopulatedToListener() {
ClientStreamListener listener = mock(ClientStreamListener.class); ClientStreamListener listener = mock(ClientStreamListener.class);
Status status = Status.UNAVAILABLE; Status status = Status.UNAVAILABLE;
ClientStream stream = new FailingClientStream(status); ClientStream stream = new FailingClientStream(status, RpcProgress.PROCESSED, tracers);
stream.start(listener); stream.start(listener);
verify(listener).closed(eq(status), eq(RpcProgress.PROCESSED), any(Metadata.class)); verify(listener).closed(eq(status), eq(RpcProgress.PROCESSED), any(Metadata.class));
} }
@ -49,7 +53,7 @@ public class FailingClientStreamTest {
ClientStreamListener listener = mock(ClientStreamListener.class); ClientStreamListener listener = mock(ClientStreamListener.class);
Status status = Status.UNAVAILABLE; Status status = Status.UNAVAILABLE;
ClientStream stream = new FailingClientStream(status, RpcProgress.DROPPED); ClientStream stream = new FailingClientStream(status, RpcProgress.DROPPED, tracers);
stream.start(listener); stream.start(listener);
verify(listener).closed(eq(status), eq(RpcProgress.DROPPED), any(Metadata.class)); verify(listener).closed(eq(status), eq(RpcProgress.DROPPED), any(Metadata.class));
} }

View File

@ -22,6 +22,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.Status; import io.grpc.Status;
import io.grpc.internal.ClientStreamListener.RpcProgress; import io.grpc.internal.ClientStreamListener.RpcProgress;
@ -41,8 +42,9 @@ public class FailingClientTransportTest {
Status error = Status.UNAVAILABLE; Status error = Status.UNAVAILABLE;
RpcProgress rpcProgress = RpcProgress.DROPPED; RpcProgress rpcProgress = RpcProgress.DROPPED;
FailingClientTransport transport = new FailingClientTransport(error, rpcProgress); FailingClientTransport transport = new FailingClientTransport(error, rpcProgress);
ClientStream stream = transport ClientStream stream = transport.newStream(
.newStream(TestMethodDescriptors.voidMethod(), new Metadata(), CallOptions.DEFAULT); TestMethodDescriptors.voidMethod(), new Metadata(), CallOptions.DEFAULT,
new ClientStreamTracer[] { new ClientStreamTracer() {} });
ClientStreamListener listener = mock(ClientStreamListener.class); ClientStreamListener listener = mock(ClientStreamListener.class);
stream.start(listener); stream.start(listener);

View File

@ -0,0 +1,49 @@
/*
* Copyright 2021 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.grpc.internal;
import static org.mockito.Mockito.mock;
import io.grpc.ClientStreamTracer;
import io.grpc.ForwardingTestUtil;
import java.lang.reflect.Method;
import java.util.Collections;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link ForwardingClientStreamTracer}. */
@RunWith(JUnit4.class)
public class ForwardingClientStreamTracerTest {
private final ClientStreamTracer mockDelegate = mock(ClientStreamTracer.class);
@Test
public void allMethodsForwarded() throws Exception {
ForwardingTestUtil.testMethodsForwarded(
ClientStreamTracer.class,
mockDelegate,
new ForwardingClientStreamTracerTest.TestClientStreamTracer(),
Collections.<Method>emptyList());
}
private final class TestClientStreamTracer extends ForwardingClientStreamTracer {
@Override
protected ClientStreamTracer delegate() {
return mockDelegate;
}
}
}

View File

@ -16,6 +16,7 @@
package io.grpc.internal; package io.grpc.internal;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
@ -27,13 +28,17 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer;
import io.grpc.ClientStreamTracer.StreamInfo;
import io.grpc.LoadBalancer.PickResult; import io.grpc.LoadBalancer.PickResult;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.Status; import io.grpc.Status;
import io.grpc.internal.ClientStreamListener.RpcProgress; import io.grpc.internal.ClientStreamListener.RpcProgress;
import io.grpc.internal.GrpcUtil.Http2Error; import io.grpc.internal.GrpcUtil.Http2Error;
import io.grpc.testing.TestMethodDescriptors; import io.grpc.testing.TestMethodDescriptors;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
@ -44,6 +49,10 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class) @RunWith(JUnit4.class)
public class GrpcUtilTest { public class GrpcUtilTest {
private static final ClientStreamTracer[] tracers = new ClientStreamTracer[] {
new ClientStreamTracer() {}
};
@SuppressWarnings("deprecation") // https://github.com/grpc/grpc-java/issues/7467 @SuppressWarnings("deprecation") // https://github.com/grpc/grpc-java/issues/7467
@Rule public final ExpectedException thrown = ExpectedException.none(); @Rule public final ExpectedException thrown = ExpectedException.none();
@ -244,8 +253,9 @@ public class GrpcUtilTest {
assertNotNull(transport); assertNotNull(transport);
ClientStream stream = transport ClientStream stream = transport.newStream(
.newStream(TestMethodDescriptors.voidMethod(), new Metadata(), CallOptions.DEFAULT); TestMethodDescriptors.voidMethod(), new Metadata(), CallOptions.DEFAULT,
tracers);
ClientStreamListener listener = mock(ClientStreamListener.class); ClientStreamListener listener = mock(ClientStreamListener.class);
stream.start(listener); stream.start(listener);
@ -260,8 +270,9 @@ public class GrpcUtilTest {
assertNotNull(transport); assertNotNull(transport);
ClientStream stream = transport ClientStream stream = transport.newStream(
.newStream(TestMethodDescriptors.voidMethod(), new Metadata(), CallOptions.DEFAULT); TestMethodDescriptors.voidMethod(), new Metadata(), CallOptions.DEFAULT,
tracers);
ClientStreamListener listener = mock(ClientStreamListener.class); ClientStreamListener listener = mock(ClientStreamListener.class);
stream.start(listener); stream.start(listener);
@ -276,11 +287,39 @@ public class GrpcUtilTest {
assertNotNull(transport); assertNotNull(transport);
ClientStream stream = transport ClientStream stream = transport.newStream(
.newStream(TestMethodDescriptors.voidMethod(), new Metadata(), CallOptions.DEFAULT); TestMethodDescriptors.voidMethod(), new Metadata(), CallOptions.DEFAULT,
tracers);
ClientStreamListener listener = mock(ClientStreamListener.class); ClientStreamListener listener = mock(ClientStreamListener.class);
stream.start(listener); stream.start(listener);
verify(listener).closed(eq(status), eq(RpcProgress.DROPPED), any(Metadata.class)); verify(listener).closed(eq(status), eq(RpcProgress.DROPPED), any(Metadata.class));
} }
@Test
public void clientStreamTracerFactoryBackwardCompatibility() {
final AtomicReference<Attributes> transportAttrsRef = new AtomicReference<>();
final ClientStreamTracer mockTracer = mock(ClientStreamTracer.class);
final Metadata.Key<String> key = Metadata.Key.of("fake-key", Metadata.ASCII_STRING_MARSHALLER);
ClientStreamTracer.Factory oldFactoryImpl = new ClientStreamTracer.Factory() {
@SuppressWarnings("deprecation")
@Override
public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata headers) {
transportAttrsRef.set(info.getTransportAttrs());
headers.put(key, "fake-value");
return mockTracer;
}
};
StreamInfo info =
StreamInfo.newBuilder().setCallOptions(CallOptions.DEFAULT.withWaitForReady()).build();
Metadata metadata = new Metadata();
Attributes transAttrs =
Attributes.newBuilder().set(Attributes.Key.<String>create("foo"), "bar").build();
ClientStreamTracer tracer = GrpcUtil.newClientStreamTracer(oldFactoryImpl, info, metadata);
tracer.streamCreated(transAttrs, metadata);
assertThat(transportAttrsRef.get()).isEqualTo(transAttrs);
assertThat(metadata.get(key)).isEqualTo("fake-value");
}
} }

View File

@ -71,6 +71,7 @@ import io.grpc.ClientCall;
import io.grpc.ClientInterceptor; import io.grpc.ClientInterceptor;
import io.grpc.ClientInterceptors; import io.grpc.ClientInterceptors;
import io.grpc.ClientStreamTracer; import io.grpc.ClientStreamTracer;
import io.grpc.ClientStreamTracer.StreamInfo;
import io.grpc.CompositeChannelCredentials; import io.grpc.CompositeChannelCredentials;
import io.grpc.ConnectivityState; import io.grpc.ConnectivityState;
import io.grpc.ConnectivityStateInfo; import io.grpc.ConnectivityStateInfo;
@ -151,6 +152,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.JUnit4; import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Captor; import org.mockito.Captor;
import org.mockito.InOrder; import org.mockito.InOrder;
import org.mockito.Mock; import org.mockito.Mock;
@ -225,6 +227,8 @@ public class ManagedChannelImplTest {
private ArgumentCaptor<Status> statusCaptor; private ArgumentCaptor<Status> statusCaptor;
@Captor @Captor
private ArgumentCaptor<CallOptions> callOptionsCaptor; private ArgumentCaptor<CallOptions> callOptionsCaptor;
@Captor
private ArgumentCaptor<ClientStreamTracer[]> tracersCaptor;
@Mock @Mock
private LoadBalancer mockLoadBalancer; private LoadBalancer mockLoadBalancer;
@Mock @Mock
@ -525,7 +529,9 @@ public class ManagedChannelImplTest {
MockClientTransportInfo transportInfo = transports.poll(); MockClientTransportInfo transportInfo = transports.poll();
ConnectionClientTransport mockTransport = transportInfo.transport; ConnectionClientTransport mockTransport = transportInfo.transport;
ManagedClientTransport.Listener transportListener = transportInfo.listener; ManagedClientTransport.Listener transportListener = transportInfo.listener;
when(mockTransport.newStream(same(method), same(headers), any(CallOptions.class))) when(mockTransport.newStream(
same(method), same(headers), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream); .thenReturn(mockStream);
transportListener.transportReady(); transportListener.transportReady();
when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class))) when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class)))
@ -534,7 +540,9 @@ public class ManagedChannelImplTest {
executor.runDueTasks(); executor.runDueTasks();
ArgumentCaptor<CallOptions> callOptionsCaptor = ArgumentCaptor.forClass(null); ArgumentCaptor<CallOptions> callOptionsCaptor = ArgumentCaptor.forClass(null);
verify(mockTransport).newStream(same(method), same(headers), callOptionsCaptor.capture()); verify(mockTransport).newStream(
same(method), same(headers), callOptionsCaptor.capture(),
ArgumentMatchers.<ClientStreamTracer[]>any());
assertThat(callOptionsCaptor.getValue().isWaitForReady()).isTrue(); assertThat(callOptionsCaptor.getValue().isWaitForReady()).isTrue();
verify(mockStream).start(streamListenerCaptor.capture()); verify(mockStream).start(streamListenerCaptor.capture());
@ -600,7 +608,9 @@ public class ManagedChannelImplTest {
MockClientTransportInfo transportInfo = transports.poll(); MockClientTransportInfo transportInfo = transports.poll();
ConnectionClientTransport mockTransport = transportInfo.transport; ConnectionClientTransport mockTransport = transportInfo.transport;
ManagedClientTransport.Listener transportListener = transportInfo.listener; ManagedClientTransport.Listener transportListener = transportInfo.listener;
when(mockTransport.newStream(same(method), same(headers), any(CallOptions.class))) when(mockTransport.newStream(
same(method), same(headers), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream); .thenReturn(mockStream);
transportListener.transportReady(); transportListener.transportReady();
when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class))) when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class)))
@ -609,7 +619,9 @@ public class ManagedChannelImplTest {
executor.runDueTasks(); executor.runDueTasks();
ArgumentCaptor<CallOptions> callOptionsCaptor = ArgumentCaptor.forClass(null); ArgumentCaptor<CallOptions> callOptionsCaptor = ArgumentCaptor.forClass(null);
verify(mockTransport).newStream(same(method), same(headers), callOptionsCaptor.capture()); verify(mockTransport).newStream(
same(method), same(headers), callOptionsCaptor.capture(),
ArgumentMatchers.<ClientStreamTracer[]>any());
assertThat(callOptionsCaptor.getValue().getOption(callOptionsKey)).isEqualTo("fooValue"); assertThat(callOptionsCaptor.getValue().getOption(callOptionsKey)).isEqualTo("fooValue");
verify(mockStream).start(streamListenerCaptor.capture()); verify(mockStream).start(streamListenerCaptor.capture());
@ -800,9 +812,13 @@ public class ManagedChannelImplTest {
ConnectionClientTransport mockTransport = transportInfo.transport; ConnectionClientTransport mockTransport = transportInfo.transport;
verify(mockTransport).start(any(ManagedClientTransport.Listener.class)); verify(mockTransport).start(any(ManagedClientTransport.Listener.class));
ManagedClientTransport.Listener transportListener = transportInfo.listener; ManagedClientTransport.Listener transportListener = transportInfo.listener;
when(mockTransport.newStream(same(method), same(headers), same(CallOptions.DEFAULT))) when(mockTransport.newStream(
same(method), same(headers), same(CallOptions.DEFAULT),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream); .thenReturn(mockStream);
when(mockTransport.newStream(same(method), same(headers2), same(CallOptions.DEFAULT))) when(mockTransport.newStream(
same(method), same(headers2), same(CallOptions.DEFAULT),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream2); .thenReturn(mockStream2);
transportListener.transportReady(); transportListener.transportReady();
when(mockPicker.pickSubchannel( when(mockPicker.pickSubchannel(
@ -820,14 +836,19 @@ public class ManagedChannelImplTest {
any(SocketAddress.class), any(ClientTransportOptions.class), any(ChannelLogger.class)); any(SocketAddress.class), any(ClientTransportOptions.class), any(ChannelLogger.class));
call.start(mockCallListener, headers); call.start(mockCallListener, headers);
verify(mockTransport, never()) verify(mockTransport, never()).newStream(
.newStream(same(method), same(headers), same(CallOptions.DEFAULT)); same(method), same(headers), same(CallOptions.DEFAULT),
ArgumentMatchers.<ClientStreamTracer[]>any());
// Second RPC, will be assigned to the real transport // Second RPC, will be assigned to the real transport
ClientCall<String, Integer> call2 = channel.newCall(method, CallOptions.DEFAULT); ClientCall<String, Integer> call2 = channel.newCall(method, CallOptions.DEFAULT);
call2.start(mockCallListener2, headers2); call2.start(mockCallListener2, headers2);
verify(mockTransport).newStream(same(method), same(headers2), same(CallOptions.DEFAULT)); verify(mockTransport).newStream(
verify(mockTransport).newStream(same(method), same(headers2), same(CallOptions.DEFAULT)); same(method), same(headers2), same(CallOptions.DEFAULT),
ArgumentMatchers.<ClientStreamTracer[]>any());
verify(mockTransport).newStream(
same(method), same(headers2), same(CallOptions.DEFAULT),
ArgumentMatchers.<ClientStreamTracer[]>any());
verify(mockStream2).start(any(ClientStreamListener.class)); verify(mockStream2).start(any(ClientStreamListener.class));
// Shutdown // Shutdown
@ -872,7 +893,9 @@ public class ManagedChannelImplTest {
.thenReturn(PickResult.withSubchannel(subchannel)); .thenReturn(PickResult.withSubchannel(subchannel));
updateBalancingStateSafely(helper, READY, picker2); updateBalancingStateSafely(helper, READY, picker2);
executor.runDueTasks(); executor.runDueTasks();
verify(mockTransport).newStream(same(method), same(headers), same(CallOptions.DEFAULT)); verify(mockTransport).newStream(
same(method), same(headers), same(CallOptions.DEFAULT),
ArgumentMatchers.<ClientStreamTracer[]>any());
verify(mockStream).start(any(ClientStreamListener.class)); verify(mockStream).start(any(ClientStreamListener.class));
} }
@ -1021,7 +1044,9 @@ public class ManagedChannelImplTest {
MockClientTransportInfo transportInfo = transports.poll(); MockClientTransportInfo transportInfo = transports.poll();
ConnectionClientTransport mockTransport = transportInfo.transport; ConnectionClientTransport mockTransport = transportInfo.transport;
ManagedClientTransport.Listener transportListener = transportInfo.listener; ManagedClientTransport.Listener transportListener = transportInfo.listener;
when(mockTransport.newStream(same(method), same(headers), any(CallOptions.class))) when(mockTransport.newStream(
same(method), same(headers), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream); .thenReturn(mockStream);
transportListener.transportReady(); transportListener.transportReady();
when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class))) when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class)))
@ -1031,7 +1056,8 @@ public class ManagedChannelImplTest {
// Real streams are started in the call executor if they were previously buffered. // Real streams are started in the call executor if they were previously buffered.
assertEquals(1, callExecutor.runDueTasks()); assertEquals(1, callExecutor.runDueTasks());
verify(mockTransport).newStream(same(method), same(headers), same(options)); verify(mockTransport).newStream(
same(method), same(headers), same(options), ArgumentMatchers.<ClientStreamTracer[]>any());
verify(mockStream).start(streamListenerCaptor.capture()); verify(mockStream).start(streamListenerCaptor.capture());
// Call listener callbacks are also run in the call executor // Call listener callbacks are also run in the call executor
@ -1298,7 +1324,8 @@ public class ManagedChannelImplTest {
same(goodAddress), any(ClientTransportOptions.class), any(ChannelLogger.class)); same(goodAddress), any(ClientTransportOptions.class), any(ChannelLogger.class));
MockClientTransportInfo goodTransportInfo = transports.poll(); MockClientTransportInfo goodTransportInfo = transports.poll();
when(goodTransportInfo.transport.newStream( when(goodTransportInfo.transport.newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class))) any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mock(ClientStream.class)); .thenReturn(mock(ClientStream.class));
goodTransportInfo.listener.transportReady(); goodTransportInfo.listener.transportReady();
@ -1310,11 +1337,13 @@ public class ManagedChannelImplTest {
// Delayed transport uses the app executor to create real streams. // Delayed transport uses the app executor to create real streams.
executor.runDueTasks(); executor.runDueTasks();
verify(goodTransportInfo.transport).newStream(same(method), same(headers), verify(goodTransportInfo.transport).newStream(
same(CallOptions.DEFAULT)); same(method), same(headers), same(CallOptions.DEFAULT),
ArgumentMatchers.<ClientStreamTracer[]>any());
// The bad transport was never used. // The bad transport was never used.
verify(badTransportInfo.transport, times(0)).newStream(any(MethodDescriptor.class), verify(badTransportInfo.transport, times(0)).newStream(
any(Metadata.class), any(CallOptions.class)); any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
} }
@Test @Test
@ -1464,10 +1493,12 @@ public class ManagedChannelImplTest {
// ... while the wait-for-ready call stays // ... while the wait-for-ready call stays
verifyNoMoreInteractions(mockCallListener); verifyNoMoreInteractions(mockCallListener);
// No real stream was ever created // No real stream was ever created
verify(transportInfo1.transport, times(0)) verify(transportInfo1.transport, times(0)).newStream(
.newStream(any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class)); any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
verify(transportInfo2.transport, times(0)) ArgumentMatchers.<ClientStreamTracer[]>any());
.newStream(any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class)); verify(transportInfo2.transport, times(0)).newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
} }
@Test @Test
@ -1763,8 +1794,9 @@ public class ManagedChannelImplTest {
assertEquals(0, balancerRpcExecutor.numPendingTasks()); assertEquals(0, balancerRpcExecutor.numPendingTasks());
transportInfo.listener.transportReady(); transportInfo.listener.transportReady();
assertEquals(1, balancerRpcExecutor.runDueTasks()); assertEquals(1, balancerRpcExecutor.runDueTasks());
verify(transportInfo.transport).newStream(same(method), same(headers), verify(transportInfo.transport).newStream(
same(CallOptions.DEFAULT)); same(method), same(headers), same(CallOptions.DEFAULT),
ArgumentMatchers.<ClientStreamTracer[]>any());
// The transport goes away // The transport goes away
transportInfo.listener.transportShutdown(Status.UNAVAILABLE); transportInfo.listener.transportShutdown(Status.UNAVAILABLE);
@ -1870,7 +1902,9 @@ public class ManagedChannelImplTest {
ClientCall<String, Integer> call = channel.newCall(method, callOptions); ClientCall<String, Integer> call = channel.newCall(method, callOptions);
call.start(mockCallListener, headers); call.start(mockCallListener, headers);
verify(transportInfo.transport).newStream(same(method), same(headers), same(callOptions)); verify(transportInfo.transport).newStream(
same(method), same(headers), same(callOptions),
ArgumentMatchers.<ClientStreamTracer[]>any());
assertThat(headers.getAll(metadataKey)) assertThat(headers.getAll(metadataKey))
.containsExactly(channelCredValue, callCredValue).inOrder(); .containsExactly(channelCredValue, callCredValue).inOrder();
@ -1887,7 +1921,9 @@ public class ManagedChannelImplTest {
transportInfo.listener.transportReady(); transportInfo.listener.transportReady();
balancerRpcExecutor.runDueTasks(); balancerRpcExecutor.runDueTasks();
verify(transportInfo.transport).newStream(same(method), same(headers), same(callOptions)); verify(transportInfo.transport).newStream(
same(method), same(headers), same(callOptions),
ArgumentMatchers.<ClientStreamTracer[]>any());
assertThat(headers.getAll(metadataKey)).containsExactly(callCredValue); assertThat(headers.getAll(metadataKey)).containsExactly(callCredValue);
oob.shutdownNow(); oob.shutdownNow();
@ -1919,7 +1955,9 @@ public class ManagedChannelImplTest {
call.start(mockCallListener2, headers); call.start(mockCallListener2, headers);
// CallOptions may contain StreamTracerFactory for census that is added by default. // CallOptions may contain StreamTracerFactory for census that is added by default.
verify(transportInfo.transport).newStream(same(method), same(headers), any(CallOptions.class)); verify(transportInfo.transport).newStream(
same(method), same(headers), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
assertThat(headers.getAll(metadataKey)).containsExactly(callCredValue); assertThat(headers.getAll(metadataKey)).containsExactly(callCredValue);
oob.shutdownNow(); oob.shutdownNow();
} }
@ -1962,7 +2000,9 @@ public class ManagedChannelImplTest {
ClientCall<String, Integer> call = channel.newCall(method, callOptions); ClientCall<String, Integer> call = channel.newCall(method, callOptions);
call.start(mockCallListener, headers); call.start(mockCallListener, headers);
verify(transportInfo.transport).newStream(same(method), same(headers), same(callOptions)); verify(transportInfo.transport).newStream(
same(method), same(headers), same(callOptions),
ArgumentMatchers.<ClientStreamTracer[]>any());
assertThat(headers.getAll(metadataKey)) assertThat(headers.getAll(metadataKey))
.containsExactly(channelCredValue, callCredValue).inOrder(); .containsExactly(channelCredValue, callCredValue).inOrder();
@ -1998,7 +2038,9 @@ public class ManagedChannelImplTest {
call.start(mockCallListener2, headers); call.start(mockCallListener2, headers);
// CallOptions may contain StreamTracerFactory for census that is added by default. // CallOptions may contain StreamTracerFactory for census that is added by default.
verify(transportInfo.transport).newStream(same(method), same(headers), any(CallOptions.class)); verify(transportInfo.transport).newStream(
same(method), same(headers), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
assertThat(headers.getAll(metadataKey)) assertThat(headers.getAll(metadataKey))
.containsExactly(oobChannelCredValue, callCredValue).inOrder(); .containsExactly(oobChannelCredValue, callCredValue).inOrder();
oob.shutdownNow(); oob.shutdownNow();
@ -2097,7 +2139,9 @@ public class ManagedChannelImplTest {
ClientCall<String, Integer> call = sChannel.newCall(method, callOptions); ClientCall<String, Integer> call = sChannel.newCall(method, callOptions);
call.start(mockCallListener, headers); call.start(mockCallListener, headers);
verify(mockTransport).newStream(same(method), same(headers), callOptionsCaptor.capture()); verify(mockTransport).newStream(
same(method), same(headers), callOptionsCaptor.capture(),
ArgumentMatchers.<ClientStreamTracer[]>any());
CallOptions capturedCallOption = callOptionsCaptor.getValue(); CallOptions capturedCallOption = callOptionsCaptor.getValue();
assertThat(capturedCallOption.getDeadline()).isSameInstanceAs(callOptions.getDeadline()); assertThat(capturedCallOption.getDeadline()).isSameInstanceAs(callOptions.getDeadline());
@ -2125,7 +2169,8 @@ public class ManagedChannelImplTest {
ClientCall<String, Integer> call = sChannel.newCall(method, CallOptions.DEFAULT); ClientCall<String, Integer> call = sChannel.newCall(method, CallOptions.DEFAULT);
call.start(mockCallListener, headers); call.start(mockCallListener, headers);
verify(mockTransport, never()).newStream( verify(mockTransport, never()).newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class)); any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
verifyNoInteractions(mockCallListener); verifyNoInteractions(mockCallListener);
assertEquals(1, balancerRpcExecutor.runDueTasks()); assertEquals(1, balancerRpcExecutor.runDueTasks());
@ -2157,7 +2202,8 @@ public class ManagedChannelImplTest {
sChannel.newCall(method, CallOptions.DEFAULT.withWaitForReady()); sChannel.newCall(method, CallOptions.DEFAULT.withWaitForReady());
call.start(mockCallListener, headers); call.start(mockCallListener, headers);
verify(mockTransport, never()).newStream( verify(mockTransport, never()).newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class)); any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
verifyNoInteractions(mockCallListener); verifyNoInteractions(mockCallListener);
assertEquals(1, balancerRpcExecutor.runDueTasks()); assertEquals(1, balancerRpcExecutor.runDueTasks());
@ -2332,7 +2378,8 @@ public class ManagedChannelImplTest {
return mock(ClientStream.class); return mock(ClientStream.class);
} }
}).when(transport).newStream( }).when(transport).newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class)); any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
verify(creds, never()).applyRequestMetadata( verify(creds, never()).applyRequestMetadata(
any(RequestInfo.class), any(Executor.class), any(CallCredentials.MetadataApplier.class)); any(RequestInfo.class), any(Executor.class), any(CallCredentials.MetadataApplier.class));
@ -2351,11 +2398,14 @@ public class ManagedChannelImplTest {
assertEquals(AUTHORITY, infoCaptor.getValue().getAuthority()); assertEquals(AUTHORITY, infoCaptor.getValue().getAuthority());
assertEquals(SecurityLevel.NONE, infoCaptor.getValue().getSecurityLevel()); assertEquals(SecurityLevel.NONE, infoCaptor.getValue().getSecurityLevel());
verify(transport, never()).newStream( verify(transport, never()).newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class)); any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
// newStream() is called after apply() is called // newStream() is called after apply() is called
applierCaptor.getValue().apply(new Metadata()); applierCaptor.getValue().apply(new Metadata());
verify(transport).newStream(same(method), any(Metadata.class), same(callOptions)); verify(transport).newStream(
same(method), any(Metadata.class), same(callOptions),
ArgumentMatchers.<ClientStreamTracer[]>any());
assertEquals("testValue", testKey.get(newStreamContexts.poll())); assertEquals("testValue", testKey.get(newStreamContexts.poll()));
// The context should not live beyond the scope of newStream() and applyRequestMetadata() // The context should not live beyond the scope of newStream() and applyRequestMetadata()
assertNull(testKey.get()); assertNull(testKey.get());
@ -2374,11 +2424,14 @@ public class ManagedChannelImplTest {
assertEquals(SecurityLevel.NONE, infoCaptor.getValue().getSecurityLevel()); assertEquals(SecurityLevel.NONE, infoCaptor.getValue().getSecurityLevel());
// This is from the first call // This is from the first call
verify(transport).newStream( verify(transport).newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class)); any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
// Still, newStream() is called after apply() is called // Still, newStream() is called after apply() is called
applierCaptor.getValue().apply(new Metadata()); applierCaptor.getValue().apply(new Metadata());
verify(transport, times(2)).newStream(same(method), any(Metadata.class), same(callOptions)); verify(transport, times(2)).newStream(
same(method), any(Metadata.class), same(callOptions),
ArgumentMatchers.<ClientStreamTracer[]>any());
assertEquals("testValue", testKey.get(newStreamContexts.poll())); assertEquals("testValue", testKey.get(newStreamContexts.poll()));
assertNull(testKey.get()); assertNull(testKey.get());
@ -2387,8 +2440,20 @@ public class ManagedChannelImplTest {
@Test @Test
public void pickerReturnsStreamTracer_noDelay() { public void pickerReturnsStreamTracer_noDelay() {
ClientStream mockStream = mock(ClientStream.class); ClientStream mockStream = mock(ClientStream.class);
ClientStreamTracer.Factory factory1 = mock(ClientStreamTracer.Factory.class); final ClientStreamTracer tracer1 = new ClientStreamTracer() {};
ClientStreamTracer.Factory factory2 = mock(ClientStreamTracer.Factory.class); final ClientStreamTracer tracer2 = new ClientStreamTracer() {};
ClientStreamTracer.Factory factory1 = new ClientStreamTracer.InternalLimitedInfoFactory() {
@Override
public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata headers) {
return tracer1;
}
};
ClientStreamTracer.Factory factory2 = new ClientStreamTracer.InternalLimitedInfoFactory() {
@Override
public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata headers) {
return tracer2;
}
};
createChannel(); createChannel();
Subchannel subchannel = Subchannel subchannel =
createSubchannelSafely(helper, addressGroup, Attributes.EMPTY, subchannelStateListener); createSubchannelSafely(helper, addressGroup, Attributes.EMPTY, subchannelStateListener);
@ -2397,7 +2462,8 @@ public class ManagedChannelImplTest {
transportInfo.listener.transportReady(); transportInfo.listener.transportReady();
ClientTransport mockTransport = transportInfo.transport; ClientTransport mockTransport = transportInfo.transport;
when(mockTransport.newStream( when(mockTransport.newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class))) any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream); .thenReturn(mockStream);
when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn( when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn(
@ -2409,20 +2475,29 @@ public class ManagedChannelImplTest {
call.start(mockCallListener, new Metadata()); call.start(mockCallListener, new Metadata());
verify(mockPicker).pickSubchannel(any(PickSubchannelArgs.class)); verify(mockPicker).pickSubchannel(any(PickSubchannelArgs.class));
verify(mockTransport).newStream(same(method), any(Metadata.class), callOptionsCaptor.capture()); verify(mockTransport).newStream(
assertEquals( same(method), any(Metadata.class), callOptionsCaptor.capture(),
Arrays.asList(factory1, factory2), tracersCaptor.capture());
callOptionsCaptor.getValue().getStreamTracerFactories()); assertThat(tracersCaptor.getValue()).isEqualTo(new ClientStreamTracer[] {tracer1, tracer2});
// The factories are safely not stubbed because we do not expect any usage of them.
verifyNoInteractions(factory1);
verifyNoInteractions(factory2);
} }
@Test @Test
public void pickerReturnsStreamTracer_delayed() { public void pickerReturnsStreamTracer_delayed() {
ClientStream mockStream = mock(ClientStream.class); ClientStream mockStream = mock(ClientStream.class);
ClientStreamTracer.Factory factory1 = mock(ClientStreamTracer.Factory.class); final ClientStreamTracer tracer1 = new ClientStreamTracer() {};
ClientStreamTracer.Factory factory2 = mock(ClientStreamTracer.Factory.class); final ClientStreamTracer tracer2 = new ClientStreamTracer() {};
ClientStreamTracer.Factory factory1 = new ClientStreamTracer.InternalLimitedInfoFactory() {
@Override
public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata headers) {
return tracer1;
}
};
ClientStreamTracer.Factory factory2 = new ClientStreamTracer.InternalLimitedInfoFactory() {
@Override
public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata headers) {
return tracer2;
}
};
createChannel(); createChannel();
CallOptions callOptions = CallOptions.DEFAULT.withStreamTracerFactory(factory1); CallOptions callOptions = CallOptions.DEFAULT.withStreamTracerFactory(factory1);
@ -2436,7 +2511,8 @@ public class ManagedChannelImplTest {
transportInfo.listener.transportReady(); transportInfo.listener.transportReady();
ClientTransport mockTransport = transportInfo.transport; ClientTransport mockTransport = transportInfo.transport;
when(mockTransport.newStream( when(mockTransport.newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class))) any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream); .thenReturn(mockStream);
when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn( when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn(
PickResult.withSubchannel(subchannel, factory2)); PickResult.withSubchannel(subchannel, factory2));
@ -2445,13 +2521,10 @@ public class ManagedChannelImplTest {
assertEquals(1, executor.runDueTasks()); assertEquals(1, executor.runDueTasks());
verify(mockPicker).pickSubchannel(any(PickSubchannelArgs.class)); verify(mockPicker).pickSubchannel(any(PickSubchannelArgs.class));
verify(mockTransport).newStream(same(method), any(Metadata.class), callOptionsCaptor.capture()); verify(mockTransport).newStream(
assertEquals( same(method), any(Metadata.class), callOptionsCaptor.capture(),
Arrays.asList(factory1, factory2), tracersCaptor.capture());
callOptionsCaptor.getValue().getStreamTracerFactories()); assertThat(tracersCaptor.getValue()).isEqualTo(new ClientStreamTracer[] {tracer1, tracer2});
// The factories are safely not stubbed because we do not expect any usage of them.
verifyNoInteractions(factory1);
verifyNoInteractions(factory2);
} }
@Test @Test
@ -2818,7 +2891,9 @@ public class ManagedChannelImplTest {
MockClientTransportInfo transportInfo = transports.poll(); MockClientTransportInfo transportInfo = transports.poll();
ConnectionClientTransport mockTransport = transportInfo.transport; ConnectionClientTransport mockTransport = transportInfo.transport;
ManagedClientTransport.Listener transportListener = transportInfo.listener; ManagedClientTransport.Listener transportListener = transportInfo.listener;
when(mockTransport.newStream(same(method), any(Metadata.class), any(CallOptions.class))) when(mockTransport.newStream(
same(method), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream); .thenReturn(mockStream);
transportListener.transportReady(); transportListener.transportReady();
@ -2829,7 +2904,9 @@ public class ManagedChannelImplTest {
executor.runDueTasks(); executor.runDueTasks();
// Verify the buffered call was drained // Verify the buffered call was drained
verify(mockTransport).newStream(same(method), any(Metadata.class), any(CallOptions.class)); verify(mockTransport).newStream(
same(method), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
verify(mockStream).start(any(ClientStreamListener.class)); verify(mockStream).start(any(ClientStreamListener.class));
} }
@ -2888,7 +2965,9 @@ public class ManagedChannelImplTest {
MockClientTransportInfo transportInfo = transports.poll(); MockClientTransportInfo transportInfo = transports.poll();
ConnectionClientTransport mockTransport = transportInfo.transport; ConnectionClientTransport mockTransport = transportInfo.transport;
ManagedClientTransport.Listener transportListener = transportInfo.listener; ManagedClientTransport.Listener transportListener = transportInfo.listener;
when(mockTransport.newStream(same(method), any(Metadata.class), any(CallOptions.class))) when(mockTransport.newStream(
same(method), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream); .thenReturn(mockStream);
transportListener.transportReady(); transportListener.transportReady();
when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class))) when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class)))
@ -2898,7 +2977,9 @@ public class ManagedChannelImplTest {
// Verify the original call was drained // Verify the original call was drained
executor.runDueTasks(); executor.runDueTasks();
verify(mockTransport).newStream(same(method), any(Metadata.class), any(CallOptions.class)); verify(mockTransport).newStream(
same(method), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
verify(mockStream).start(any(ClientStreamListener.class)); verify(mockStream).start(any(ClientStreamListener.class));
} }
@ -2920,7 +3001,9 @@ public class ManagedChannelImplTest {
MockClientTransportInfo transportInfo = transports.poll(); MockClientTransportInfo transportInfo = transports.poll();
ConnectionClientTransport mockTransport = transportInfo.transport; ConnectionClientTransport mockTransport = transportInfo.transport;
ManagedClientTransport.Listener transportListener = transportInfo.listener; ManagedClientTransport.Listener transportListener = transportInfo.listener;
when(mockTransport.newStream(same(method), any(Metadata.class), any(CallOptions.class))) when(mockTransport.newStream(
same(method), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream); .thenReturn(mockStream);
transportListener.transportReady(); transportListener.transportReady();
@ -2929,8 +3012,9 @@ public class ManagedChannelImplTest {
updateBalancingStateSafely(helper, READY, mockPicker); updateBalancingStateSafely(helper, READY, mockPicker);
executor.runDueTasks(); executor.runDueTasks();
verify(mockTransport, never()) verify(mockTransport, never()).newStream(
.newStream(any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class)); any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
verify(mockStream, never()).start(any(ClientStreamListener.class)); verify(mockStream, never()).start(any(ClientStreamListener.class));
@ -2939,7 +3023,9 @@ public class ManagedChannelImplTest {
updateBalancingStateSafely(helper, READY, mockPicker); updateBalancingStateSafely(helper, READY, mockPicker);
executor.runDueTasks(); executor.runDueTasks();
verify(mockTransport).newStream(same(method), any(Metadata.class), any(CallOptions.class)); verify(mockTransport).newStream(
same(method), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
verify(mockStream).start(any(ClientStreamListener.class)); verify(mockStream).start(any(ClientStreamListener.class));
} }
@ -2958,7 +3044,9 @@ public class ManagedChannelImplTest {
MockClientTransportInfo transportInfo = transports.poll(); MockClientTransportInfo transportInfo = transports.poll();
ConnectionClientTransport mockTransport = transportInfo.transport; ConnectionClientTransport mockTransport = transportInfo.transport;
ManagedClientTransport.Listener transportListener = transportInfo.listener; ManagedClientTransport.Listener transportListener = transportInfo.listener;
when(mockTransport.newStream(same(method), any(Metadata.class), any(CallOptions.class))) when(mockTransport.newStream(
same(method), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream); .thenReturn(mockStream);
transportListener.transportReady(); transportListener.transportReady();
@ -2973,7 +3061,9 @@ public class ManagedChannelImplTest {
updateBalancingStateSafely(helper, READY, mockPicker); updateBalancingStateSafely(helper, READY, mockPicker);
executor.runDueTasks(); executor.runDueTasks();
verify(mockTransport).newStream(same(method), any(Metadata.class), any(CallOptions.class)); verify(mockTransport).newStream(
same(method), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any());
verify(mockStream).start(any(ClientStreamListener.class)); verify(mockStream).start(any(ClientStreamListener.class));
} }
@ -3405,7 +3495,8 @@ public class ManagedChannelImplTest {
transportInfo.listener.transportReady(); transportInfo.listener.transportReady();
ClientTransport mockTransport = transportInfo.transport; ClientTransport mockTransport = transportInfo.transport;
when(mockTransport.newStream( when(mockTransport.newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class))) any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream); .thenReturn(mockStream);
when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn( when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn(
PickResult.withSubchannel(subchannel, factory)); PickResult.withSubchannel(subchannel, factory));
@ -3478,7 +3569,9 @@ public class ManagedChannelImplTest {
MockClientTransportInfo transportInfo = transports.poll(); MockClientTransportInfo transportInfo = transports.poll();
ConnectionClientTransport mockTransport = transportInfo.transport; ConnectionClientTransport mockTransport = transportInfo.transport;
ManagedClientTransport.Listener transportListener = transportInfo.listener; ManagedClientTransport.Listener transportListener = transportInfo.listener;
when(mockTransport.newStream(same(method), same(headers), any(CallOptions.class))) when(mockTransport.newStream(
same(method), same(headers), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream); .thenReturn(mockStream);
// subchannel stat bumped when call gets assigned to it // subchannel stat bumped when call gets assigned to it
@ -3650,7 +3743,9 @@ public class ManagedChannelImplTest {
ConnectionClientTransport mockTransport = transportInfo.transport; ConnectionClientTransport mockTransport = transportInfo.transport;
ClientStream mockStream = mock(ClientStream.class); ClientStream mockStream = mock(ClientStream.class);
ClientStream mockStream2 = mock(ClientStream.class); ClientStream mockStream2 = mock(ClientStream.class);
when(mockTransport.newStream(same(method), any(Metadata.class), any(CallOptions.class))) when(mockTransport.newStream(
same(method), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream).thenReturn(mockStream2); .thenReturn(mockStream).thenReturn(mockStream2);
transportInfo.listener.transportReady(); transportInfo.listener.transportReady();
updateBalancingStateSafely(helper, READY, mockPicker); updateBalancingStateSafely(helper, READY, mockPicker);
@ -3754,7 +3849,9 @@ public class ManagedChannelImplTest {
ConnectionClientTransport mockTransport = transportInfo.transport; ConnectionClientTransport mockTransport = transportInfo.transport;
ClientStream mockStream = mock(ClientStream.class); ClientStream mockStream = mock(ClientStream.class);
ClientStream mockStream2 = mock(ClientStream.class); ClientStream mockStream2 = mock(ClientStream.class);
when(mockTransport.newStream(same(method), any(Metadata.class), any(CallOptions.class))) when(mockTransport.newStream(
same(method), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mockStream).thenReturn(mockStream2); .thenReturn(mockStream).thenReturn(mockStream2);
transportInfo.listener.transportReady(); transportInfo.listener.transportReady();
updateBalancingStateSafely(helper, READY, mockPicker); updateBalancingStateSafely(helper, READY, mockPicker);

View File

@ -163,9 +163,10 @@ public class RetriableStreamTest {
} }
@Override @Override
ClientStream newSubstream(ClientStreamTracer.Factory tracerFactory, Metadata metadata) { ClientStream newSubstream(
Metadata metadata, ClientStreamTracer.Factory tracerFactory, boolean isTransparentRetry) {
bufferSizeTracer = bufferSizeTracer =
tracerFactory.newClientStreamTracer(STREAM_INFO, new Metadata()); tracerFactory.newClientStreamTracer(STREAM_INFO, metadata);
int actualPreviousRpcAttemptsInHeader = metadata.get(GRPC_PREVIOUS_RPC_ATTEMPTS) == null int actualPreviousRpcAttemptsInHeader = metadata.get(GRPC_PREVIOUS_RPC_ATTEMPTS) == null
? 0 : Integer.valueOf(metadata.get(GRPC_PREVIOUS_RPC_ATTEMPTS)); ? 0 : Integer.valueOf(metadata.get(GRPC_PREVIOUS_RPC_ATTEMPTS));
return retriableStreamRecorder.newSubstream(actualPreviousRpcAttemptsInHeader); return retriableStreamRecorder.newSubstream(actualPreviousRpcAttemptsInHeader);

View File

@ -23,6 +23,7 @@ import static org.mockito.Mockito.when;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ChannelLogger; import io.grpc.ChannelLogger;
import io.grpc.ClientStreamTracer;
import io.grpc.InternalLogId; import io.grpc.InternalLogId;
import io.grpc.LoadBalancer.PickResult; import io.grpc.LoadBalancer.PickResult;
import io.grpc.LoadBalancer.PickSubchannelArgs; import io.grpc.LoadBalancer.PickSubchannelArgs;
@ -35,6 +36,7 @@ import java.net.SocketAddress;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.mockito.ArgumentMatchers;
import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
@ -118,7 +120,8 @@ public final class TestUtils {
when(mockTransport.getLogId()) when(mockTransport.getLogId())
.thenReturn(InternalLogId.allocate("mocktransport", /*details=*/ null)); .thenReturn(InternalLogId.allocate("mocktransport", /*details=*/ null));
when(mockTransport.newStream( when(mockTransport.newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class))) any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
ArgumentMatchers.<ClientStreamTracer[]>any()))
.thenReturn(mock(ClientStream.class)); .thenReturn(mock(ClientStream.class));
// Save the listener // Save the listener
doAnswer(new Answer<Runnable>() { doAnswer(new Answer<Runnable>() {

View File

@ -40,6 +40,7 @@ public class ForwardingClientStreamTracerTest {
Collections.<Method>emptyList()); Collections.<Method>emptyList());
} }
@SuppressWarnings("deprecation")
private final class TestClientStreamTracer extends ForwardingClientStreamTracer { private final class TestClientStreamTracer extends ForwardingClientStreamTracer {
@Override @Override
protected ClientStreamTracer delegate() { protected ClientStreamTracer delegate() {

View File

@ -21,6 +21,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
import io.grpc.Attributes; import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer;
import io.grpc.InternalChannelz.SocketStats; import io.grpc.InternalChannelz.SocketStats;
import io.grpc.InternalLogId; import io.grpc.InternalLogId;
import io.grpc.Metadata; import io.grpc.Metadata;
@ -118,7 +119,7 @@ class CronetClientTransport implements ConnectionClientTransport {
@Override @Override
public CronetClientStream newStream(final MethodDescriptor<?, ?> method, final Metadata headers, public CronetClientStream newStream(final MethodDescriptor<?, ?> method, final Metadata headers,
final CallOptions callOptions) { final CallOptions callOptions, ClientStreamTracer[] tracers) {
Preconditions.checkNotNull(method, "method"); Preconditions.checkNotNull(method, "method");
Preconditions.checkNotNull(headers, "headers"); Preconditions.checkNotNull(headers, "headers");
@ -126,7 +127,7 @@ class CronetClientTransport implements ConnectionClientTransport {
final String url = "https://" + authority + defaultPath; final String url = "https://" + authority + defaultPath;
final StatsTraceContext statsTraceCtx = final StatsTraceContext statsTraceCtx =
StatsTraceContext.newClientContext(callOptions, attrs, headers); StatsTraceContext.newClientContext(tracers, attrs, headers);
class StartCallback implements Runnable { class StartCallback implements Runnable {
final CronetClientStream clientStream = new CronetClientStream( final CronetClientStream clientStream = new CronetClientStream(
url, userAgent, executor, headers, CronetClientTransport.this, this, lock, maxMessageSize, url, userAgent, executor, headers, CronetClientTransport.this, this, lock, maxMessageSize,

View File

@ -25,6 +25,7 @@ import static org.mockito.Mockito.mock;
import android.os.Build; import android.os.Build;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ChannelLogger; import io.grpc.ChannelLogger;
import io.grpc.ClientStreamTracer;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.MethodDescriptor; import io.grpc.MethodDescriptor;
import io.grpc.cronet.CronetChannelBuilder.CronetTransportFactory; import io.grpc.cronet.CronetChannelBuilder.CronetTransportFactory;
@ -50,6 +51,8 @@ public final class CronetChannelBuilderTest {
@Mock private ExperimentalCronetEngine mockEngine; @Mock private ExperimentalCronetEngine mockEngine;
@Mock private ChannelLogger channelLogger; @Mock private ChannelLogger channelLogger;
private final ClientStreamTracer[] tracers =
new ClientStreamTracer[]{ new ClientStreamTracer() {} };
private MethodDescriptor<?, ?> method = TestMethodDescriptors.voidMethod(); private MethodDescriptor<?, ?> method = TestMethodDescriptors.voidMethod();
@Before @Before
@ -69,7 +72,8 @@ public final class CronetChannelBuilderTest {
new InetSocketAddress("localhost", 443), new InetSocketAddress("localhost", 443),
new ClientTransportOptions(), new ClientTransportOptions(),
channelLogger); channelLogger);
CronetClientStream stream = transport.newStream(method, new Metadata(), CallOptions.DEFAULT); CronetClientStream stream = transport.newStream(
method, new Metadata(), CallOptions.DEFAULT, tracers);
assertTrue(stream.idempotent); assertTrue(stream.idempotent);
} }
@ -85,7 +89,8 @@ public final class CronetChannelBuilderTest {
new InetSocketAddress("localhost", 443), new InetSocketAddress("localhost", 443),
new ClientTransportOptions(), new ClientTransportOptions(),
channelLogger); channelLogger);
CronetClientStream stream = transport.newStream(method, new Metadata(), CallOptions.DEFAULT); CronetClientStream stream = transport.newStream(
method, new Metadata(), CallOptions.DEFAULT, tracers);
assertFalse(stream.idempotent); assertFalse(stream.idempotent);
} }

View File

@ -27,6 +27,7 @@ import static org.mockito.Mockito.when;
import android.os.Build; import android.os.Build;
import io.grpc.Attributes; import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.MethodDescriptor; import io.grpc.MethodDescriptor;
import io.grpc.SecurityLevel; import io.grpc.SecurityLevel;
@ -60,6 +61,8 @@ public final class CronetClientTransportTest {
private static final Attributes EAG_ATTRS = private static final Attributes EAG_ATTRS =
Attributes.newBuilder().set(EAG_ATTR_KEY, "value").build(); Attributes.newBuilder().set(EAG_ATTR_KEY, "value").build();
private final ClientStreamTracer[] tracers =
new ClientStreamTracer[]{ new ClientStreamTracer() {} };
private CronetClientTransport transport; private CronetClientTransport transport;
@Mock private StreamBuilderFactory streamFactory; @Mock private StreamBuilderFactory streamFactory;
@Mock private Executor executor; @Mock private Executor executor;
@ -101,9 +104,9 @@ public final class CronetClientTransportTest {
@Test @Test
public void shutdownTransport() throws Exception { public void shutdownTransport() throws Exception {
CronetClientStream stream1 = CronetClientStream stream1 =
transport.newStream(descriptor, new Metadata(), CallOptions.DEFAULT); transport.newStream(descriptor, new Metadata(), CallOptions.DEFAULT, tracers);
CronetClientStream stream2 = CronetClientStream stream2 =
transport.newStream(descriptor, new Metadata(), CallOptions.DEFAULT); transport.newStream(descriptor, new Metadata(), CallOptions.DEFAULT, tracers);
// Create a transport and start two streams on it. // Create a transport and start two streams on it.
ArgumentCaptor<BidirectionalStream.Callback> callbackCaptor = ArgumentCaptor<BidirectionalStream.Callback> callbackCaptor =
@ -137,7 +140,7 @@ public final class CronetClientTransportTest {
@Test @Test
public void startStreamAfterShutdown() throws Exception { public void startStreamAfterShutdown() throws Exception {
CronetClientStream stream = CronetClientStream stream =
transport.newStream(descriptor, new Metadata(), CallOptions.DEFAULT); transport.newStream(descriptor, new Metadata(), CallOptions.DEFAULT, tracers);
transport.shutdown(); transport.shutdown();
BaseClientStreamListener listener = new BaseClientStreamListener(); BaseClientStreamListener listener = new BaseClientStreamListener();
stream.start(listener); stream.start(listener);

View File

@ -37,7 +37,7 @@ import javax.annotation.concurrent.ThreadSafe;
* span of an LB stream with the remote load-balancer. * span of an LB stream with the remote load-balancer.
*/ */
@ThreadSafe @ThreadSafe
final class GrpclbClientLoadRecorder extends ClientStreamTracer.Factory { final class GrpclbClientLoadRecorder extends ClientStreamTracer.InternalLimitedInfoFactory {
private static final AtomicLongFieldUpdater<GrpclbClientLoadRecorder> callsStartedUpdater = private static final AtomicLongFieldUpdater<GrpclbClientLoadRecorder> callsStartedUpdater =
AtomicLongFieldUpdater.newUpdater(GrpclbClientLoadRecorder.class, "callsStarted"); AtomicLongFieldUpdater.newUpdater(GrpclbClientLoadRecorder.class, "callsStarted");

View File

@ -22,6 +22,7 @@ import com.google.common.base.Objects;
import io.grpc.Attributes; import io.grpc.Attributes;
import io.grpc.ClientStreamTracer; import io.grpc.ClientStreamTracer;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.internal.ForwardingClientStreamTracer;
import io.grpc.internal.GrpcAttributes; import io.grpc.internal.GrpcAttributes;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -29,7 +30,7 @@ import javax.annotation.Nullable;
* Wraps a {@link ClientStreamTracer.Factory}, retrieves tokens from transport attributes and * Wraps a {@link ClientStreamTracer.Factory}, retrieves tokens from transport attributes and
* attaches them to headers. This is only used in the PICK_FIRST mode. * attaches them to headers. This is only used in the PICK_FIRST mode.
*/ */
final class TokenAttachingTracerFactory extends ClientStreamTracer.Factory { final class TokenAttachingTracerFactory extends ClientStreamTracer.InternalLimitedInfoFactory {
private static final ClientStreamTracer NOOP_TRACER = new ClientStreamTracer() {}; private static final ClientStreamTracer NOOP_TRACER = new ClientStreamTracer() {};
@Nullable @Nullable
@ -42,19 +43,30 @@ final class TokenAttachingTracerFactory extends ClientStreamTracer.Factory {
@Override @Override
public ClientStreamTracer newClientStreamTracer( public ClientStreamTracer newClientStreamTracer(
ClientStreamTracer.StreamInfo info, Metadata headers) { ClientStreamTracer.StreamInfo info, Metadata headers) {
Attributes transportAttrs = checkNotNull(info.getTransportAttrs(), "transportAttrs"); if (delegate == null) {
Attributes eagAttrs =
checkNotNull(transportAttrs.get(GrpcAttributes.ATTR_CLIENT_EAG_ATTRS), "eagAttrs");
String token = eagAttrs.get(GrpclbConstants.TOKEN_ATTRIBUTE_KEY);
headers.discardAll(GrpclbConstants.TOKEN_METADATA_KEY);
if (token != null) {
headers.put(GrpclbConstants.TOKEN_METADATA_KEY, token);
}
if (delegate != null) {
return delegate.newClientStreamTracer(info, headers);
} else {
return NOOP_TRACER; return NOOP_TRACER;
} }
final ClientStreamTracer clientStreamTracer = delegate.newClientStreamTracer(info, headers);
class TokenPropagationTracer extends ForwardingClientStreamTracer {
@Override
protected ClientStreamTracer delegate() {
return clientStreamTracer;
}
@Override
public void streamCreated(Attributes transportAttrs, Metadata headers) {
Attributes eagAttrs =
checkNotNull(transportAttrs.get(GrpcAttributes.ATTR_CLIENT_EAG_ATTRS), "eagAttrs");
String token = eagAttrs.get(GrpclbConstants.TOKEN_ATTRIBUTE_KEY);
headers.discardAll(GrpclbConstants.TOKEN_METADATA_KEY);
if (token != null) {
headers.put(GrpclbConstants.TOKEN_METADATA_KEY, token);
}
delegate().streamCreated(transportAttrs, headers);
}
}
return new TokenPropagationTracer();
} }
@Override @Override

View File

@ -481,6 +481,7 @@ public class GrpclbLoadBalancerTest {
ClientStreamTracer tracer1 = ClientStreamTracer tracer1 =
pick1.getStreamTracerFactory().newClientStreamTracer(STREAM_INFO, new Metadata()); pick1.getStreamTracerFactory().newClientStreamTracer(STREAM_INFO, new Metadata());
tracer1.streamCreated(Attributes.EMPTY, new Metadata());
PickResult pick2 = picker.pickSubchannel(args); PickResult pick2 = picker.pickSubchannel(args);
assertNull(pick2.getSubchannel()); assertNull(pick2.getSubchannel());
@ -504,6 +505,7 @@ public class GrpclbLoadBalancerTest {
assertSame(getLoadRecorder(), pick3.getStreamTracerFactory()); assertSame(getLoadRecorder(), pick3.getStreamTracerFactory());
ClientStreamTracer tracer3 = ClientStreamTracer tracer3 =
pick3.getStreamTracerFactory().newClientStreamTracer(STREAM_INFO, new Metadata()); pick3.getStreamTracerFactory().newClientStreamTracer(STREAM_INFO, new Metadata());
tracer3.streamCreated(Attributes.EMPTY, new Metadata());
// pick3 has sent out headers // pick3 has sent out headers
tracer3.outboundHeaders(); tracer3.outboundHeaders();
@ -541,6 +543,7 @@ public class GrpclbLoadBalancerTest {
assertSame(getLoadRecorder(), pick5.getStreamTracerFactory()); assertSame(getLoadRecorder(), pick5.getStreamTracerFactory());
ClientStreamTracer tracer5 = ClientStreamTracer tracer5 =
pick5.getStreamTracerFactory().newClientStreamTracer(STREAM_INFO, new Metadata()); pick5.getStreamTracerFactory().newClientStreamTracer(STREAM_INFO, new Metadata());
tracer5.streamCreated(Attributes.EMPTY, new Metadata());
// pick3 ended without receiving response headers // pick3 ended without receiving response headers
tracer3.streamClosed(Status.DEADLINE_EXCEEDED); tracer3.streamClosed(Status.DEADLINE_EXCEEDED);

View File

@ -33,12 +33,23 @@ import org.junit.runners.JUnit4;
/** Unit tests for {@link TokenAttachingTracerFactory}. */ /** Unit tests for {@link TokenAttachingTracerFactory}. */
@RunWith(JUnit4.class) @RunWith(JUnit4.class)
public class TokenAttachingTracerFactoryTest { public class TokenAttachingTracerFactoryTest {
private static final ClientStreamTracer fakeTracer = new ClientStreamTracer() {}; private static final class FakeClientStreamTracer extends ClientStreamTracer {
Attributes transportAttrs;
Metadata headers;
@Override
public void streamCreated(Attributes transportAttrs, Metadata headers) {
this.transportAttrs = transportAttrs;
this.headers = headers;
}
}
private static final FakeClientStreamTracer fakeTracer = new FakeClientStreamTracer();
private final ClientStreamTracer.Factory delegate = mock( private final ClientStreamTracer.Factory delegate = mock(
ClientStreamTracer.Factory.class, ClientStreamTracer.Factory.class,
delegatesTo( delegatesTo(
new ClientStreamTracer.Factory() { new ClientStreamTracer.InternalLimitedInfoFactory() {
@Override @Override
public ClientStreamTracer newClientStreamTracer( public ClientStreamTracer newClientStreamTracer(
ClientStreamTracer.StreamInfo info, Metadata headers) { ClientStreamTracer.StreamInfo info, Metadata headers) {
@ -51,28 +62,25 @@ public class TokenAttachingTracerFactoryTest {
TokenAttachingTracerFactory factory = new TokenAttachingTracerFactory(delegate); TokenAttachingTracerFactory factory = new TokenAttachingTracerFactory(delegate);
Attributes eagAttrs = Attributes.newBuilder() Attributes eagAttrs = Attributes.newBuilder()
.set(GrpclbConstants.TOKEN_ATTRIBUTE_KEY, "token0001").build(); .set(GrpclbConstants.TOKEN_ATTRIBUTE_KEY, "token0001").build();
ClientStreamTracer.StreamInfo info = ClientStreamTracer.StreamInfo.newBuilder() ClientStreamTracer.StreamInfo info = ClientStreamTracer.StreamInfo.newBuilder().build();
.setTransportAttrs(
Attributes.newBuilder().set(GrpcAttributes.ATTR_CLIENT_EAG_ATTRS, eagAttrs).build())
.build();
Metadata headers = new Metadata(); Metadata headers = new Metadata();
// Preexisting token should be replaced // Preexisting token should be replaced
headers.put(GrpclbConstants.TOKEN_METADATA_KEY, "preexisting-token"); headers.put(GrpclbConstants.TOKEN_METADATA_KEY, "preexisting-token");
ClientStreamTracer tracer = factory.newClientStreamTracer(info, headers); ClientStreamTracer tracer = factory.newClientStreamTracer(info, headers);
verify(delegate).newClientStreamTracer(same(info), same(headers)); verify(delegate).newClientStreamTracer(same(info), same(headers));
assertThat(tracer).isSameInstanceAs(fakeTracer); Attributes transportAttrs =
Attributes.newBuilder().set(GrpcAttributes.ATTR_CLIENT_EAG_ATTRS, eagAttrs).build();
tracer.streamCreated(transportAttrs, headers);
assertThat(fakeTracer.transportAttrs).isSameInstanceAs(transportAttrs);
assertThat(fakeTracer.headers).isSameInstanceAs(headers);
assertThat(headers.getAll(GrpclbConstants.TOKEN_METADATA_KEY)).containsExactly("token0001"); assertThat(headers.getAll(GrpclbConstants.TOKEN_METADATA_KEY)).containsExactly("token0001");
} }
@Test @Test
public void noToken() { public void noToken() {
TokenAttachingTracerFactory factory = new TokenAttachingTracerFactory(delegate); TokenAttachingTracerFactory factory = new TokenAttachingTracerFactory(delegate);
ClientStreamTracer.StreamInfo info = ClientStreamTracer.StreamInfo.newBuilder() ClientStreamTracer.StreamInfo info = ClientStreamTracer.StreamInfo.newBuilder().build();
.setTransportAttrs(
Attributes.newBuilder()
.set(GrpcAttributes.ATTR_CLIENT_EAG_ATTRS, Attributes.EMPTY).build())
.build();
Metadata headers = new Metadata(); Metadata headers = new Metadata();
// Preexisting token should be removed // Preexisting token should be removed
@ -80,22 +88,25 @@ public class TokenAttachingTracerFactoryTest {
ClientStreamTracer tracer = factory.newClientStreamTracer(info, headers); ClientStreamTracer tracer = factory.newClientStreamTracer(info, headers);
verify(delegate).newClientStreamTracer(same(info), same(headers)); verify(delegate).newClientStreamTracer(same(info), same(headers));
assertThat(tracer).isSameInstanceAs(fakeTracer); Attributes transportAttrs =
Attributes.newBuilder().set(GrpcAttributes.ATTR_CLIENT_EAG_ATTRS, Attributes.EMPTY).build();
tracer.streamCreated(transportAttrs, headers);
assertThat(fakeTracer.transportAttrs).isSameInstanceAs(transportAttrs);
assertThat(fakeTracer.headers).isSameInstanceAs(headers);
assertThat(headers.get(GrpclbConstants.TOKEN_METADATA_KEY)).isNull(); assertThat(headers.get(GrpclbConstants.TOKEN_METADATA_KEY)).isNull();
} }
@Test @Test
public void nullDelegate() { public void nullDelegate() {
TokenAttachingTracerFactory factory = new TokenAttachingTracerFactory(null); TokenAttachingTracerFactory factory = new TokenAttachingTracerFactory(null);
ClientStreamTracer.StreamInfo info = ClientStreamTracer.StreamInfo.newBuilder() ClientStreamTracer.StreamInfo info = ClientStreamTracer.StreamInfo.newBuilder().build();
.setTransportAttrs(
Attributes.newBuilder()
.set(GrpcAttributes.ATTR_CLIENT_EAG_ATTRS, Attributes.EMPTY).build())
.build();
Metadata headers = new Metadata(); Metadata headers = new Metadata();
ClientStreamTracer tracer = factory.newClientStreamTracer(info, headers); ClientStreamTracer tracer = factory.newClientStreamTracer(info, headers);
tracer.streamCreated(
Attributes.newBuilder().set(GrpcAttributes.ATTR_CLIENT_EAG_ATTRS, Attributes.EMPTY).build(),
headers);
assertThat(tracer).isNotNull(); assertThat(tracer).isNotNull();
assertThat(headers.get(GrpclbConstants.TOKEN_METADATA_KEY)).isNull(); assertThat(headers.get(GrpclbConstants.TOKEN_METADATA_KEY)).isNull();
} }

View File

@ -289,7 +289,7 @@ public abstract class AbstractInteropTest {
new LinkedBlockingQueue<>(); new LinkedBlockingQueue<>();
private final ClientStreamTracer.Factory clientStreamTracerFactory = private final ClientStreamTracer.Factory clientStreamTracerFactory =
new ClientStreamTracer.Factory() { new ClientStreamTracer.InternalLimitedInfoFactory() {
@Override @Override
public ClientStreamTracer newClientStreamTracer( public ClientStreamTracer newClientStreamTracer(
ClientStreamTracer.StreamInfo info, Metadata headers) { ClientStreamTracer.StreamInfo info, Metadata headers) {
@ -375,7 +375,8 @@ public abstract class AbstractInteropTest {
.getClientInterceptor( .getClientInterceptor(
tagger, tagContextBinarySerializer, clientStatsRecorder, tagger, tagContextBinarySerializer, clientStatsRecorder,
GrpcUtil.STOPWATCH_SUPPLIER, GrpcUtil.STOPWATCH_SUPPLIER,
true, true, true, false /* real-time metrics */); true, true, true,
/* recordRealTimeMetrics= */ false);
} }
protected final ServerStreamTracer.Factory createCustomCensusTracerFactory() { protected final ServerStreamTracer.Factory createCustomCensusTracerFactory() {
@ -1179,6 +1180,7 @@ public abstract class AbstractInteropTest {
public void deadlineExceededServerStreaming() throws Exception { public void deadlineExceededServerStreaming() throws Exception {
// warm up the channel and JVM // warm up the channel and JVM
blockingStub.emptyCall(Empty.getDefaultInstance()); blockingStub.emptyCall(Empty.getDefaultInstance());
assertStatsTrace("grpc.testing.TestService/EmptyCall", Status.Code.OK);
ResponseParameters.Builder responseParameters = ResponseParameters.newBuilder() ResponseParameters.Builder responseParameters = ResponseParameters.newBuilder()
.setSize(1) .setSize(1)
.setIntervalUs(10000); .setIntervalUs(10000);
@ -1195,7 +1197,6 @@ public abstract class AbstractInteropTest {
recorder.awaitCompletion(); recorder.awaitCompletion();
assertEquals(Status.DEADLINE_EXCEEDED.getCode(), assertEquals(Status.DEADLINE_EXCEEDED.getCode(),
Status.fromThrowable(recorder.getError()).getCode()); Status.fromThrowable(recorder.getError()).getCode());
assertStatsTrace("grpc.testing.TestService/EmptyCall", Status.Code.OK);
if (metricsExpected()) { if (metricsExpected()) {
// Stream may not have been created when deadline is exceeded, thus we don't check tracer // Stream may not have been created when deadline is exceeded, thus we don't check tracer
// stats. // stats.
@ -1239,6 +1240,12 @@ public abstract class AbstractInteropTest {
// warm up the channel // warm up the channel
blockingStub.emptyCall(Empty.getDefaultInstance()); blockingStub.emptyCall(Empty.getDefaultInstance());
if (metricsExpected()) {
// clientStartRecord
clientStatsRecorder.pollRecord(5, TimeUnit.SECONDS);
// clientEndRecord
clientStatsRecorder.pollRecord(5, TimeUnit.SECONDS);
}
try { try {
blockingStub blockingStub
.withDeadlineAfter(-10, TimeUnit.SECONDS) .withDeadlineAfter(-10, TimeUnit.SECONDS)
@ -1249,7 +1256,6 @@ public abstract class AbstractInteropTest {
assertThat(ex.getStatus().getDescription()) assertThat(ex.getStatus().getDescription())
.startsWith("ClientCall started after deadline exceeded"); .startsWith("ClientCall started after deadline exceeded");
} }
assertStatsTrace("grpc.testing.TestService/EmptyCall", Status.Code.OK);
if (metricsExpected()) { if (metricsExpected()) {
MetricsRecord clientStartRecord = clientStatsRecorder.pollRecord(5, TimeUnit.SECONDS); MetricsRecord clientStartRecord = clientStatsRecorder.pollRecord(5, TimeUnit.SECONDS);
checkStartTags(clientStartRecord, "grpc.testing.TestService/EmptyCall", true); checkStartTags(clientStartRecord, "grpc.testing.TestService/EmptyCall", true);

View File

@ -28,6 +28,7 @@ import com.google.common.util.concurrent.SettableFuture;
import io.grpc.Attributes; import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ChannelLogger; import io.grpc.ChannelLogger;
import io.grpc.ClientStreamTracer;
import io.grpc.InternalChannelz.SocketStats; import io.grpc.InternalChannelz.SocketStats;
import io.grpc.InternalLogId; import io.grpc.InternalLogId;
import io.grpc.Metadata; import io.grpc.Metadata;
@ -167,14 +168,15 @@ class NettyClientTransport implements ConnectionClientTransport {
@Override @Override
public ClientStream newStream( public ClientStream newStream(
MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions) { MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions,
ClientStreamTracer[] tracers) {
Preconditions.checkNotNull(method, "method"); Preconditions.checkNotNull(method, "method");
Preconditions.checkNotNull(headers, "headers"); Preconditions.checkNotNull(headers, "headers");
if (channel == null) { if (channel == null) {
return new FailingClientStream(statusExplainingWhyTheChannelIsNull); return new FailingClientStream(statusExplainingWhyTheChannelIsNull, tracers);
} }
StatsTraceContext statsTraceCtx = StatsTraceContext statsTraceCtx =
StatsTraceContext.newClientContext(callOptions, getAttributes(), headers); StatsTraceContext.newClientContext(tracers, getAttributes(), headers);
return new NettyClientStream( return new NettyClientStream(
new NettyClientStream.TransportState( new NettyClientStream.TransportState(
handler, handler,

View File

@ -41,6 +41,7 @@ import com.google.common.util.concurrent.SettableFuture;
import io.grpc.Attributes; import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ChannelLogger; import io.grpc.ChannelLogger;
import io.grpc.ClientStreamTracer;
import io.grpc.Grpc; import io.grpc.Grpc;
import io.grpc.InternalChannelz; import io.grpc.InternalChannelz;
import io.grpc.Metadata; import io.grpc.Metadata;
@ -828,7 +829,9 @@ public class NettyClientTransportTest {
} }
Rpc(NettyClientTransport transport, Metadata headers) { Rpc(NettyClientTransport transport, Metadata headers) {
stream = transport.newStream(METHOD, headers, CallOptions.DEFAULT); stream = transport.newStream(
METHOD, headers, CallOptions.DEFAULT,
new ClientStreamTracer[]{ new ClientStreamTracer() {} });
stream.start(listener); stream.start(listener);
stream.request(1); stream.request(1);
stream.writeMessage(new ByteArrayInputStream(MESSAGE.getBytes(UTF_8))); stream.writeMessage(new ByteArrayInputStream(MESSAGE.getBytes(UTF_8)));

View File

@ -34,6 +34,7 @@ import com.squareup.okhttp.Request;
import com.squareup.okhttp.internal.http.StatusLine; import com.squareup.okhttp.internal.http.StatusLine;
import io.grpc.Attributes; import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer;
import io.grpc.Grpc; import io.grpc.Grpc;
import io.grpc.HttpConnectProxiedSocketAddress; import io.grpc.HttpConnectProxiedSocketAddress;
import io.grpc.InternalChannelz; import io.grpc.InternalChannelz;
@ -387,12 +388,13 @@ class OkHttpClientTransport implements ConnectionClientTransport, TransportExcep
} }
@Override @Override
public OkHttpClientStream newStream(final MethodDescriptor<?, ?> method, public OkHttpClientStream newStream(
final Metadata headers, CallOptions callOptions) { MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions,
ClientStreamTracer[] tracers) {
Preconditions.checkNotNull(method, "method"); Preconditions.checkNotNull(method, "method");
Preconditions.checkNotNull(headers, "headers"); Preconditions.checkNotNull(headers, "headers");
StatsTraceContext statsTraceCtx = StatsTraceContext statsTraceContext =
StatsTraceContext.newClientContext(callOptions, attributes, headers); StatsTraceContext.newClientContext(tracers, getAttributes(), headers);
// FIXME: it is likely wrong to pass the transportTracer here as it'll exit the lock's scope // FIXME: it is likely wrong to pass the transportTracer here as it'll exit the lock's scope
synchronized (lock) { // to make @GuardedBy linter happy synchronized (lock) { // to make @GuardedBy linter happy
return new OkHttpClientStream( return new OkHttpClientStream(
@ -406,7 +408,7 @@ class OkHttpClientTransport implements ConnectionClientTransport, TransportExcep
initialWindowSize, initialWindowSize,
defaultAuthority, defaultAuthority,
userAgent, userAgent,
statsTraceCtx, statsTraceContext,
transportTracer, transportTracer,
callOptions, callOptions,
useGetForSafeMethods); useGetForSafeMethods);

View File

@ -56,6 +56,7 @@ import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
import io.grpc.Attributes; import io.grpc.Attributes;
import io.grpc.CallOptions; import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer;
import io.grpc.HttpConnectProxiedSocketAddress; import io.grpc.HttpConnectProxiedSocketAddress;
import io.grpc.InternalChannelz.SocketStats; import io.grpc.InternalChannelz.SocketStats;
import io.grpc.InternalChannelz.TransportStats; import io.grpc.InternalChannelz.TransportStats;
@ -146,6 +147,9 @@ public class OkHttpClientTransportTest {
private static final int DEFAULT_MAX_INBOUND_METADATA_SIZE = Integer.MAX_VALUE; private static final int DEFAULT_MAX_INBOUND_METADATA_SIZE = Integer.MAX_VALUE;
private static final Attributes EAG_ATTRS = Attributes.EMPTY; private static final Attributes EAG_ATTRS = Attributes.EMPTY;
private static final Logger logger = Logger.getLogger(OkHttpClientTransport.class.getName()); private static final Logger logger = Logger.getLogger(OkHttpClientTransport.class.getName());
private static final ClientStreamTracer[] tracers = new ClientStreamTracer[] {
new ClientStreamTracer() {}
};
@Rule public final Timeout globalTimeout = Timeout.seconds(10); @Rule public final Timeout globalTimeout = Timeout.seconds(10);
@ -299,7 +303,7 @@ public class OkHttpClientTransportTest {
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
stream.request(1); stream.request(1);
@ -387,7 +391,7 @@ public class OkHttpClientTransportTest {
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
stream.request(1); stream.request(1);
assertContainStream(3); assertContainStream(3);
@ -443,11 +447,11 @@ public class OkHttpClientTransportTest {
MockStreamListener listener1 = new MockStreamListener(); MockStreamListener listener1 = new MockStreamListener();
MockStreamListener listener2 = new MockStreamListener(); MockStreamListener listener2 = new MockStreamListener();
OkHttpClientStream stream1 = OkHttpClientStream stream1 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream1.start(listener1); stream1.start(listener1);
stream1.request(1); stream1.request(1);
OkHttpClientStream stream2 = OkHttpClientStream stream2 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream2.start(listener2); stream2.start(listener2);
stream2.request(1); stream2.request(1);
assertEquals(2, activeStreamCount()); assertEquals(2, activeStreamCount());
@ -477,7 +481,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
stream.request(1); stream.request(1);
assertEquals(1, activeStreamCount()); assertEquals(1, activeStreamCount());
@ -498,7 +502,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
stream.request(1); stream.request(1);
frameReader.nextFrameAtEndOfStream(); frameReader.nextFrameAtEndOfStream();
@ -516,7 +520,7 @@ public class OkHttpClientTransportTest {
final String message = "Hello Client"; final String message = "Hello Client";
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
stream.request(numMessages); stream.request(numMessages);
assertContainStream(3); assertContainStream(3);
@ -566,7 +570,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
stream.request(1); stream.request(1);
assertContainStream(3); assertContainStream(3);
@ -590,7 +594,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
stream.request(1); stream.request(1);
assertContainStream(3); assertContainStream(3);
@ -610,7 +614,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
assertContainStream(3); assertContainStream(3);
frameHandler().headers(true, true, 3, 0, grpcResponseTrailers(), HeadersMode.HTTP_20_HEADERS); frameHandler().headers(true, true, 3, 0, grpcResponseTrailers(), HeadersMode.HTTP_20_HEADERS);
@ -624,7 +628,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
assertContainStream(3); assertContainStream(3);
frameHandler().rstStream(3, ErrorCode.PROTOCOL_ERROR); frameHandler().rstStream(3, ErrorCode.PROTOCOL_ERROR);
@ -641,7 +645,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
assertContainStream(3); assertContainStream(3);
frameHandler().headers(false, false, 3, 0, grpcResponseHeaders(), HeadersMode.HTTP_20_HEADERS); frameHandler().headers(false, false, 3, 0, grpcResponseHeaders(), HeadersMode.HTTP_20_HEADERS);
@ -661,7 +665,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
getStream(3).cancel(Status.CANCELLED); getStream(3).cancel(Status.CANCELLED);
verify(frameWriter, timeout(TIME_OUT_MS)).rstStream(eq(3), eq(ErrorCode.CANCEL)); verify(frameWriter, timeout(TIME_OUT_MS)).rstStream(eq(3), eq(ErrorCode.CANCEL));
@ -676,7 +680,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
Header userAgentHeader = new Header(GrpcUtil.USER_AGENT_KEY.name(), Header userAgentHeader = new Header(GrpcUtil.USER_AGENT_KEY.name(),
GrpcUtil.getGrpcUserAgent("okhttp", null)); GrpcUtil.getGrpcUserAgent("okhttp", null));
@ -695,7 +699,7 @@ public class OkHttpClientTransportTest {
startTransport(3, null, true, DEFAULT_MAX_MESSAGE_SIZE, INITIAL_WINDOW_SIZE, "fakeUserAgent"); startTransport(3, null, true, DEFAULT_MAX_MESSAGE_SIZE, INITIAL_WINDOW_SIZE, "fakeUserAgent");
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
List<Header> expectedHeaders = Arrays.asList(HTTP_SCHEME_HEADER, METHOD_HEADER, List<Header> expectedHeaders = Arrays.asList(HTTP_SCHEME_HEADER, METHOD_HEADER,
new Header(Header.TARGET_AUTHORITY, "notarealauthority:80"), new Header(Header.TARGET_AUTHORITY, "notarealauthority:80"),
@ -714,7 +718,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
getStream(3).cancel(Status.DEADLINE_EXCEEDED); getStream(3).cancel(Status.DEADLINE_EXCEEDED);
verify(frameWriter, timeout(TIME_OUT_MS)).rstStream(eq(3), eq(ErrorCode.CANCEL)); verify(frameWriter, timeout(TIME_OUT_MS)).rstStream(eq(3), eq(ErrorCode.CANCEL));
@ -728,7 +732,7 @@ public class OkHttpClientTransportTest {
final String message = "Hello Server"; final String message = "Hello Server";
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
InputStream input = new ByteArrayInputStream(message.getBytes(UTF_8)); InputStream input = new ByteArrayInputStream(message.getBytes(UTF_8));
assertEquals(12, input.available()); assertEquals(12, input.available());
@ -772,12 +776,12 @@ public class OkHttpClientTransportTest {
MockStreamListener listener1 = new MockStreamListener(); MockStreamListener listener1 = new MockStreamListener();
MockStreamListener listener2 = new MockStreamListener(); MockStreamListener listener2 = new MockStreamListener();
OkHttpClientStream stream1 = OkHttpClientStream stream1 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream1.start(listener1); stream1.start(listener1);
stream1.request(2); stream1.request(2);
OkHttpClientStream stream2 = OkHttpClientStream stream2 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream2.start(listener2); stream2.start(listener2);
stream2.request(2); stream2.request(2);
assertEquals(2, activeStreamCount()); assertEquals(2, activeStreamCount());
@ -838,7 +842,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
int messageLength = INITIAL_WINDOW_SIZE / 2 + 1; int messageLength = INITIAL_WINDOW_SIZE / 2 + 1;
byte[] fakeMessage = new byte[messageLength]; byte[] fakeMessage = new byte[messageLength];
@ -874,7 +878,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
// Outbound window always starts at 65535 until changed by Settings.INITIAL_WINDOW_SIZE // Outbound window always starts at 65535 until changed by Settings.INITIAL_WINDOW_SIZE
@ -920,7 +924,7 @@ public class OkHttpClientTransportTest {
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
int messageLength = 75; int messageLength = 75;
@ -963,7 +967,7 @@ public class OkHttpClientTransportTest {
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
int messageLength = 100000; int messageLength = 100000;
@ -999,7 +1003,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
int messageLength = 20; int messageLength = 20;
setInitialWindowSize(HEADER_LENGTH + 10); setInitialWindowSize(HEADER_LENGTH + 10);
@ -1045,7 +1049,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
int messageLength = 20; int messageLength = 20;
setInitialWindowSize(HEADER_LENGTH + 10); setInitialWindowSize(HEADER_LENGTH + 10);
@ -1080,10 +1084,10 @@ public class OkHttpClientTransportTest {
MockStreamListener listener1 = new MockStreamListener(); MockStreamListener listener1 = new MockStreamListener();
MockStreamListener listener2 = new MockStreamListener(); MockStreamListener listener2 = new MockStreamListener();
OkHttpClientStream stream1 = OkHttpClientStream stream1 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream1.start(listener1); stream1.start(listener1);
OkHttpClientStream stream2 = OkHttpClientStream stream2 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream2.start(listener2); stream2.start(listener2);
assertEquals(2, activeStreamCount()); assertEquals(2, activeStreamCount());
clientTransport.shutdown(SHUTDOWN_REASON); clientTransport.shutdown(SHUTDOWN_REASON);
@ -1110,11 +1114,11 @@ public class OkHttpClientTransportTest {
MockStreamListener listener1 = new MockStreamListener(); MockStreamListener listener1 = new MockStreamListener();
MockStreamListener listener2 = new MockStreamListener(); MockStreamListener listener2 = new MockStreamListener();
OkHttpClientStream stream1 = OkHttpClientStream stream1 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream1.start(listener1); stream1.start(listener1);
stream1.request(1); stream1.request(1);
OkHttpClientStream stream2 = OkHttpClientStream stream2 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream2.start(listener2); stream2.start(listener2);
stream2.request(1); stream2.request(1);
assertEquals(2, activeStreamCount()); assertEquals(2, activeStreamCount());
@ -1168,7 +1172,7 @@ public class OkHttpClientTransportTest {
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
stream.request(1); stream.request(1);
@ -1204,11 +1208,11 @@ public class OkHttpClientTransportTest {
final MockStreamListener listener1 = new MockStreamListener(); final MockStreamListener listener1 = new MockStreamListener();
final MockStreamListener listener2 = new MockStreamListener(); final MockStreamListener listener2 = new MockStreamListener();
OkHttpClientStream stream1 = OkHttpClientStream stream1 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream1.start(listener1); stream1.start(listener1);
// The second stream should be pending. // The second stream should be pending.
OkHttpClientStream stream2 = OkHttpClientStream stream2 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream2.start(listener2); stream2.start(listener2);
String sentMessage = "hello"; String sentMessage = "hello";
InputStream input = new ByteArrayInputStream(sentMessage.getBytes(UTF_8)); InputStream input = new ByteArrayInputStream(sentMessage.getBytes(UTF_8));
@ -1241,7 +1245,7 @@ public class OkHttpClientTransportTest {
setMaxConcurrentStreams(0); setMaxConcurrentStreams(0);
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
waitForStreamPending(1); waitForStreamPending(1);
stream.cancel(Status.CANCELLED); stream.cancel(Status.CANCELLED);
@ -1260,11 +1264,11 @@ public class OkHttpClientTransportTest {
final MockStreamListener listener1 = new MockStreamListener(); final MockStreamListener listener1 = new MockStreamListener();
final MockStreamListener listener2 = new MockStreamListener(); final MockStreamListener listener2 = new MockStreamListener();
OkHttpClientStream stream1 = OkHttpClientStream stream1 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream1.start(listener1); stream1.start(listener1);
// The second stream should be pending. // The second stream should be pending.
OkHttpClientStream stream2 = OkHttpClientStream stream2 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream2.start(listener2); stream2.start(listener2);
waitForStreamPending(1); waitForStreamPending(1);
@ -1290,7 +1294,7 @@ public class OkHttpClientTransportTest {
final MockStreamListener listener = new MockStreamListener(); final MockStreamListener listener = new MockStreamListener();
// The second stream should be pending. // The second stream should be pending.
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
waitForStreamPending(1); waitForStreamPending(1);
@ -1314,15 +1318,15 @@ public class OkHttpClientTransportTest {
final MockStreamListener listener3 = new MockStreamListener(); final MockStreamListener listener3 = new MockStreamListener();
OkHttpClientStream stream1 = OkHttpClientStream stream1 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream1.start(listener1); stream1.start(listener1);
// The second and third stream should be pending. // The second and third stream should be pending.
OkHttpClientStream stream2 = OkHttpClientStream stream2 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream2.start(listener2); stream2.start(listener2);
OkHttpClientStream stream3 = OkHttpClientStream stream3 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream3.start(listener3); stream3.start(listener3);
waitForStreamPending(2); waitForStreamPending(2);
@ -1346,7 +1350,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
stream.request(1); stream.request(1);
@ -1398,7 +1402,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
verify(frameWriter, timeout(TIME_OUT_MS)).synStream( verify(frameWriter, timeout(TIME_OUT_MS)).synStream(
eq(false), eq(false), eq(3), eq(0), ArgumentMatchers.<Header>anyList()); eq(false), eq(false), eq(3), eq(0), ArgumentMatchers.<Header>anyList());
@ -1415,7 +1419,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
stream.request(1); stream.request(1);
Buffer buffer = createMessageFrame(new byte[1]); Buffer buffer = createMessageFrame(new byte[1]);
@ -1437,7 +1441,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
stream.request(1); stream.request(1);
Buffer buffer = createMessageFrame(new byte[1]); Buffer buffer = createMessageFrame(new byte[1]);
@ -1459,7 +1463,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
stream.request(1); stream.request(1);
Buffer buffer = createMessageFrame(new byte[1000]); Buffer buffer = createMessageFrame(new byte[1000]);
@ -1480,7 +1484,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
stream.cancel(Status.CANCELLED); stream.cancel(Status.CANCELLED);
@ -1507,7 +1511,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
stream.cancel(Status.CANCELLED); stream.cancel(Status.CANCELLED);
// This should be ignored. // This should be ignored.
@ -1527,7 +1531,7 @@ public class OkHttpClientTransportTest {
initTransport(); initTransport();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
assertTrue(stream.isReady()); assertTrue(stream.isReady());
assertTrue(listener.isOnReadyCalled()); assertTrue(listener.isOnReadyCalled());
@ -1545,7 +1549,7 @@ public class OkHttpClientTransportTest {
setInitialWindowSize(0); setInitialWindowSize(0);
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
assertTrue(stream.isReady()); assertTrue(stream.isReady());
// Be notified at the beginning. // Be notified at the beginning.
@ -1695,7 +1699,7 @@ public class OkHttpClientTransportTest {
final String message = "Hello Server"; final String message = "Hello Server";
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
InputStream input = new ByteArrayInputStream(message.getBytes(UTF_8)); InputStream input = new ByteArrayInputStream(message.getBytes(UTF_8));
stream.writeMessage(input); stream.writeMessage(input);
@ -1720,7 +1724,7 @@ public class OkHttpClientTransportTest {
final String message = "Hello Server"; final String message = "Hello Server";
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
InputStream input = new ByteArrayInputStream(message.getBytes(UTF_8)); InputStream input = new ByteArrayInputStream(message.getBytes(UTF_8));
stream.writeMessage(input); stream.writeMessage(input);
@ -1738,7 +1742,7 @@ public class OkHttpClientTransportTest {
initTransportAndDelayConnected(); initTransportAndDelayConnected();
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
clientTransport.shutdown(SHUTDOWN_REASON); clientTransport.shutdown(SHUTDOWN_REASON);
allowTransportConnected(); allowTransportConnected();
@ -1810,7 +1814,8 @@ public class OkHttpClientTransportTest {
assertTrue(status.getCause().toString(), status.getCause() instanceof IOException); assertTrue(status.getCause().toString(), status.getCause() instanceof IOException);
MockStreamListener streamListener = new MockStreamListener(); MockStreamListener streamListener = new MockStreamListener();
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT).start(streamListener); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers)
.start(streamListener);
streamListener.waitUntilStreamClosed(); streamListener.waitUntilStreamClosed();
assertEquals(Status.UNAVAILABLE.getCode(), streamListener.status.getCode()); assertEquals(Status.UNAVAILABLE.getCode(), streamListener.status.getCode());
} }
@ -2054,13 +2059,13 @@ public class OkHttpClientTransportTest {
MockStreamListener listener2 = new MockStreamListener(); MockStreamListener listener2 = new MockStreamListener();
MockStreamListener listener3 = new MockStreamListener(); MockStreamListener listener3 = new MockStreamListener();
OkHttpClientStream stream1 = OkHttpClientStream stream1 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream1.start(listener1); stream1.start(listener1);
OkHttpClientStream stream2 = OkHttpClientStream stream2 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream2.start(listener2); stream2.start(listener2);
OkHttpClientStream stream3 = OkHttpClientStream stream3 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream3.start(listener3); stream3.start(listener3);
waitForStreamPending(1); waitForStreamPending(1);
@ -2094,13 +2099,13 @@ public class OkHttpClientTransportTest {
MockStreamListener listener2 = new MockStreamListener(); MockStreamListener listener2 = new MockStreamListener();
MockStreamListener listener3 = new MockStreamListener(); MockStreamListener listener3 = new MockStreamListener();
OkHttpClientStream stream1 = OkHttpClientStream stream1 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream1.start(listener1); stream1.start(listener1);
OkHttpClientStream stream2 = OkHttpClientStream stream2 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream2.start(listener2); stream2.start(listener2);
OkHttpClientStream stream3 = OkHttpClientStream stream3 =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream3.start(listener3); stream3.start(listener3);
assertEquals(3, activeStreamCount()); assertEquals(3, activeStreamCount());
@ -2158,7 +2163,7 @@ public class OkHttpClientTransportTest {
private void assertNewStreamFail() throws Exception { private void assertNewStreamFail() throws Exception {
MockStreamListener listener = new MockStreamListener(); MockStreamListener listener = new MockStreamListener();
OkHttpClientStream stream = OkHttpClientStream stream =
clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT, tracers);
stream.start(listener); stream.start(listener);
listener.waitUntilStreamClosed(); listener.waitUntilStreamClosed();
assertFalse(listener.status.isOk()); assertFalse(listener.status.isOk());

View File

@ -31,8 +31,8 @@ import io.grpc.InternalLogId;
import io.grpc.LoadBalancer; import io.grpc.LoadBalancer;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.Status; import io.grpc.Status;
import io.grpc.internal.ForwardingClientStreamTracer;
import io.grpc.internal.ObjectPool; import io.grpc.internal.ObjectPool;
import io.grpc.util.ForwardingClientStreamTracer;
import io.grpc.util.ForwardingLoadBalancerHelper; import io.grpc.util.ForwardingLoadBalancerHelper;
import io.grpc.util.ForwardingSubchannel; import io.grpc.util.ForwardingSubchannel;
import io.grpc.xds.ClusterImplLoadBalancerProvider.ClusterImplConfig; import io.grpc.xds.ClusterImplLoadBalancerProvider.ClusterImplConfig;
@ -329,7 +329,8 @@ final class ClusterImplLoadBalancer extends LoadBalancer {
} }
} }
private static final class CountingStreamTracerFactory extends ClientStreamTracer.Factory { private static final class CountingStreamTracerFactory extends
ClientStreamTracer.InternalLimitedInfoFactory {
private ClusterLocalityStats stats; private ClusterLocalityStats stats;
private final AtomicLong inFlights; private final AtomicLong inFlights;
@Nullable @Nullable

View File

@ -25,8 +25,8 @@ import io.grpc.ClientStreamTracer;
import io.grpc.ClientStreamTracer.StreamInfo; import io.grpc.ClientStreamTracer.StreamInfo;
import io.grpc.LoadBalancer; import io.grpc.LoadBalancer;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.internal.ForwardingClientStreamTracer;
import io.grpc.protobuf.ProtoUtils; import io.grpc.protobuf.ProtoUtils;
import io.grpc.util.ForwardingClientStreamTracer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -37,7 +37,7 @@ import java.util.List;
abstract class OrcaPerRequestUtil { abstract class OrcaPerRequestUtil {
private static final ClientStreamTracer NOOP_CLIENT_STREAM_TRACER = new ClientStreamTracer() {}; private static final ClientStreamTracer NOOP_CLIENT_STREAM_TRACER = new ClientStreamTracer() {};
private static final ClientStreamTracer.Factory NOOP_CLIENT_STREAM_TRACER_FACTORY = private static final ClientStreamTracer.Factory NOOP_CLIENT_STREAM_TRACER_FACTORY =
new ClientStreamTracer.Factory() { new ClientStreamTracer.InternalLimitedInfoFactory() {
@Override @Override
public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata headers) { public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata headers) {
return NOOP_CLIENT_STREAM_TRACER; return NOOP_CLIENT_STREAM_TRACER;
@ -189,7 +189,8 @@ abstract class OrcaPerRequestUtil {
* per-request ORCA reports and push to registered listeners for calls they trace. * per-request ORCA reports and push to registered listeners for calls they trace.
*/ */
@VisibleForTesting @VisibleForTesting
static final class OrcaReportingTracerFactory extends ClientStreamTracer.Factory { static final class OrcaReportingTracerFactory extends
ClientStreamTracer.InternalLimitedInfoFactory {
@VisibleForTesting @VisibleForTesting
static final Metadata.Key<OrcaLoadReport> ORCA_ENDPOINT_LOAD_METRICS_KEY = static final Metadata.Key<OrcaLoadReport> ORCA_ENDPOINT_LOAD_METRICS_KEY =

View File

@ -341,8 +341,8 @@ public class ClusterImplLoadBalancerTest {
PickResult result = currentPicker.pickSubchannel(mock(PickSubchannelArgs.class)); PickResult result = currentPicker.pickSubchannel(mock(PickSubchannelArgs.class));
assertThat(result.getStatus().isOk()).isTrue(); assertThat(result.getStatus().isOk()).isTrue();
ClientStreamTracer.Factory streamTracerFactory = result.getStreamTracerFactory(); ClientStreamTracer.Factory streamTracerFactory = result.getStreamTracerFactory();
streamTracerFactory.newClientStreamTracer(ClientStreamTracer.StreamInfo.newBuilder().build(), streamTracerFactory.newClientStreamTracer(
new Metadata()); ClientStreamTracer.StreamInfo.newBuilder().build(), new Metadata());
} }
ClusterStats clusterStats = ClusterStats clusterStats =
Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER)); Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER));
@ -429,8 +429,8 @@ public class ClusterImplLoadBalancerTest {
PickResult result = currentPicker.pickSubchannel(mock(PickSubchannelArgs.class)); PickResult result = currentPicker.pickSubchannel(mock(PickSubchannelArgs.class));
assertThat(result.getStatus().isOk()).isTrue(); assertThat(result.getStatus().isOk()).isTrue();
ClientStreamTracer.Factory streamTracerFactory = result.getStreamTracerFactory(); ClientStreamTracer.Factory streamTracerFactory = result.getStreamTracerFactory();
streamTracerFactory.newClientStreamTracer(ClientStreamTracer.StreamInfo.newBuilder().build(), streamTracerFactory.newClientStreamTracer(
new Metadata()); ClientStreamTracer.StreamInfo.newBuilder().build(), new Metadata());
} }
ClusterStats clusterStats = ClusterStats clusterStats =
Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER)); Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER));