mirror of https://github.com/grpc/grpc-java.git
inprocess,core: add ability to pass status cause to client
Closes #5439
This commit is contained in:
parent
a9250c1f99
commit
16b6145064
|
|
@ -70,6 +70,7 @@ public final class InProcessChannelBuilder extends
|
||||||
private final String name;
|
private final String name;
|
||||||
private ScheduledExecutorService scheduledExecutorService;
|
private ScheduledExecutorService scheduledExecutorService;
|
||||||
private int maxInboundMetadataSize = Integer.MAX_VALUE;
|
private int maxInboundMetadataSize = Integer.MAX_VALUE;
|
||||||
|
private boolean transportIncludeStatusCause = false;
|
||||||
|
|
||||||
private InProcessChannelBuilder(String name) {
|
private InProcessChannelBuilder(String name) {
|
||||||
super(new InProcessSocketAddress(name), "localhost");
|
super(new InProcessSocketAddress(name), "localhost");
|
||||||
|
|
@ -157,11 +158,30 @@ public final class InProcessChannelBuilder extends
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether to include the cause with the status that is propagated
|
||||||
|
* forward from the InProcessTransport. This was added to make debugging failing
|
||||||
|
* tests easier by showing the cause of the status.
|
||||||
|
*
|
||||||
|
* <p>By default, this is set to false.
|
||||||
|
* A default value of false maintains consistency with other transports which strip causal
|
||||||
|
* information from the status to avoid leaking information to untrusted clients, and
|
||||||
|
* to avoid sharing language-specific information with the client.
|
||||||
|
* For the in-process implementation, this is not a concern.
|
||||||
|
*
|
||||||
|
* @param enable whether to include cause in status
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public InProcessChannelBuilder propagateCauseWithStatus(boolean enable) {
|
||||||
|
this.transportIncludeStatusCause = enable;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Internal
|
@Internal
|
||||||
protected ClientTransportFactory buildTransportFactory() {
|
protected ClientTransportFactory buildTransportFactory() {
|
||||||
return new InProcessClientTransportFactory(
|
return new InProcessClientTransportFactory(
|
||||||
name, scheduledExecutorService, maxInboundMetadataSize);
|
name, scheduledExecutorService, maxInboundMetadataSize, transportIncludeStatusCause);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -173,16 +193,18 @@ public final class InProcessChannelBuilder extends
|
||||||
private final boolean useSharedTimer;
|
private final boolean useSharedTimer;
|
||||||
private final int maxInboundMetadataSize;
|
private final int maxInboundMetadataSize;
|
||||||
private boolean closed;
|
private boolean closed;
|
||||||
|
private boolean includeCauseWithStatus;
|
||||||
|
|
||||||
private InProcessClientTransportFactory(
|
private InProcessClientTransportFactory(
|
||||||
String name,
|
String name,
|
||||||
@Nullable ScheduledExecutorService scheduledExecutorService,
|
@Nullable ScheduledExecutorService scheduledExecutorService,
|
||||||
int maxInboundMetadataSize) {
|
int maxInboundMetadataSize, boolean includeCauseWithStatus) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
useSharedTimer = scheduledExecutorService == null;
|
useSharedTimer = scheduledExecutorService == null;
|
||||||
timerService = useSharedTimer
|
timerService = useSharedTimer
|
||||||
? SharedResourceHolder.get(GrpcUtil.TIMER_SERVICE) : scheduledExecutorService;
|
? SharedResourceHolder.get(GrpcUtil.TIMER_SERVICE) : scheduledExecutorService;
|
||||||
this.maxInboundMetadataSize = maxInboundMetadataSize;
|
this.maxInboundMetadataSize = maxInboundMetadataSize;
|
||||||
|
this.includeCauseWithStatus = includeCauseWithStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -194,7 +216,7 @@ public final class InProcessChannelBuilder extends
|
||||||
// TODO(carl-mastrangelo): Pass channelLogger in.
|
// TODO(carl-mastrangelo): Pass channelLogger in.
|
||||||
return new InProcessTransport(
|
return new InProcessTransport(
|
||||||
name, maxInboundMetadataSize, options.getAuthority(), options.getUserAgent(),
|
name, maxInboundMetadataSize, options.getAuthority(), options.getUserAgent(),
|
||||||
options.getEagAttributes());
|
options.getEagAttributes(), includeCauseWithStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ final class InProcessTransport implements ServerTransport, ConnectionClientTrans
|
||||||
private final String userAgent;
|
private final String userAgent;
|
||||||
private final Optional<ServerListener> optionalServerListener;
|
private final Optional<ServerListener> optionalServerListener;
|
||||||
private int serverMaxInboundMetadataSize;
|
private int serverMaxInboundMetadataSize;
|
||||||
|
private final boolean includeCauseWithStatus;
|
||||||
private ObjectPool<ScheduledExecutorService> serverSchedulerPool;
|
private ObjectPool<ScheduledExecutorService> serverSchedulerPool;
|
||||||
private ScheduledExecutorService serverScheduler;
|
private ScheduledExecutorService serverScheduler;
|
||||||
private ServerTransportListener serverTransportListener;
|
private ServerTransportListener serverTransportListener;
|
||||||
|
|
@ -115,7 +116,8 @@ final class InProcessTransport implements ServerTransport, ConnectionClientTrans
|
||||||
};
|
};
|
||||||
|
|
||||||
private InProcessTransport(String name, int maxInboundMetadataSize, String authority,
|
private InProcessTransport(String name, int maxInboundMetadataSize, String authority,
|
||||||
String userAgent, Attributes eagAttrs, Optional<ServerListener> optionalServerListener) {
|
String userAgent, Attributes eagAttrs,
|
||||||
|
Optional<ServerListener> optionalServerListener, boolean includeCauseWithStatus) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.clientMaxInboundMetadataSize = maxInboundMetadataSize;
|
this.clientMaxInboundMetadataSize = maxInboundMetadataSize;
|
||||||
this.authority = authority;
|
this.authority = authority;
|
||||||
|
|
@ -129,13 +131,14 @@ final class InProcessTransport implements ServerTransport, ConnectionClientTrans
|
||||||
.build();
|
.build();
|
||||||
this.optionalServerListener = optionalServerListener;
|
this.optionalServerListener = optionalServerListener;
|
||||||
logId = InternalLogId.allocate(getClass(), name);
|
logId = InternalLogId.allocate(getClass(), name);
|
||||||
|
this.includeCauseWithStatus = includeCauseWithStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InProcessTransport(
|
public InProcessTransport(
|
||||||
String name, int maxInboundMetadataSize, String authority, String userAgent,
|
String name, int maxInboundMetadataSize, String authority, String userAgent,
|
||||||
Attributes eagAttrs) {
|
Attributes eagAttrs, boolean includeCauseWithStatus) {
|
||||||
this(name, maxInboundMetadataSize, authority, userAgent, eagAttrs,
|
this(name, maxInboundMetadataSize, authority, userAgent, eagAttrs,
|
||||||
Optional.<ServerListener>absent());
|
Optional.<ServerListener>absent(), includeCauseWithStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
InProcessTransport(
|
InProcessTransport(
|
||||||
|
|
@ -143,7 +146,8 @@ final class InProcessTransport implements ServerTransport, ConnectionClientTrans
|
||||||
Attributes eagAttrs, ObjectPool<ScheduledExecutorService> serverSchedulerPool,
|
Attributes eagAttrs, ObjectPool<ScheduledExecutorService> serverSchedulerPool,
|
||||||
List<ServerStreamTracer.Factory> serverStreamTracerFactories,
|
List<ServerStreamTracer.Factory> serverStreamTracerFactories,
|
||||||
ServerListener serverListener) {
|
ServerListener serverListener) {
|
||||||
this(name, maxInboundMetadataSize, authority, userAgent, eagAttrs, Optional.of(serverListener));
|
this(name, maxInboundMetadataSize, authority, userAgent, eagAttrs,
|
||||||
|
Optional.of(serverListener), false);
|
||||||
this.serverMaxInboundMetadataSize = maxInboundMetadataSize;
|
this.serverMaxInboundMetadataSize = maxInboundMetadataSize;
|
||||||
this.serverSchedulerPool = serverSchedulerPool;
|
this.serverSchedulerPool = serverSchedulerPool;
|
||||||
this.serverStreamTracerFactories = serverStreamTracerFactories;
|
this.serverStreamTracerFactories = serverStreamTracerFactories;
|
||||||
|
|
@ -564,7 +568,7 @@ final class InProcessTransport implements ServerTransport, ConnectionClientTrans
|
||||||
|
|
||||||
/** clientStream.serverClosed() must be called before this method */
|
/** clientStream.serverClosed() must be called before this method */
|
||||||
private void notifyClientClose(Status status, Metadata trailers) {
|
private void notifyClientClose(Status status, Metadata trailers) {
|
||||||
Status clientStatus = stripCause(status);
|
Status clientStatus = cleanStatus(status, includeCauseWithStatus);
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (closed) {
|
if (closed) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -744,7 +748,7 @@ final class InProcessTransport implements ServerTransport, ConnectionClientTrans
|
||||||
// Must be thread-safe for shutdownNow()
|
// Must be thread-safe for shutdownNow()
|
||||||
@Override
|
@Override
|
||||||
public void cancel(Status reason) {
|
public void cancel(Status reason) {
|
||||||
Status serverStatus = stripCause(reason);
|
Status serverStatus = cleanStatus(reason, includeCauseWithStatus);
|
||||||
if (!internalCancel(serverStatus, serverStatus)) {
|
if (!internalCancel(serverStatus, serverStatus)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -843,19 +847,25 @@ final class InProcessTransport implements ServerTransport, ConnectionClientTrans
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new status with the same code and description, but stripped of any other information
|
* Returns a new status with the same code and description.
|
||||||
* (i.e. cause).
|
* If includeCauseWithStatus is true, cause is also included.
|
||||||
*
|
*
|
||||||
* <p>This is, so that the InProcess transport behaves in the same way as the other transports,
|
* <p>For InProcess transport to behave in the same way as the other transports,
|
||||||
* when exchanging statuses between client and server and vice versa.
|
* when exchanging statuses between client and server and vice versa,
|
||||||
|
* the cause should be excluded from the status.
|
||||||
|
* For easier debugging, the status may be optionally included.
|
||||||
*/
|
*/
|
||||||
private static Status stripCause(Status status) {
|
private static Status cleanStatus(Status status, boolean includeCauseWithStatus) {
|
||||||
if (status == null) {
|
if (status == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return Status
|
Status clientStatus = Status
|
||||||
.fromCodeValue(status.getCode().value())
|
.fromCodeValue(status.getCode().value())
|
||||||
.withDescription(status.getDescription());
|
.withDescription(status.getDescription());
|
||||||
|
if (includeCauseWithStatus) {
|
||||||
|
clientStatus = clientStatus.withCause(status.getCause());
|
||||||
|
}
|
||||||
|
return clientStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class SingleMessageProducer implements StreamListener.MessageProducer {
|
private static class SingleMessageProducer implements StreamListener.MessageProducer {
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,6 @@ public final class ServerImpl extends io.grpc.Server implements InternalInstrume
|
||||||
this.channelz = builder.channelz;
|
this.channelz = builder.channelz;
|
||||||
this.serverCallTracer = builder.callTracerFactory.create();
|
this.serverCallTracer = builder.callTracerFactory.create();
|
||||||
this.ticker = checkNotNull(builder.ticker, "ticker");
|
this.ticker = checkNotNull(builder.ticker, "ticker");
|
||||||
|
|
||||||
channelz.addServer(this);
|
channelz.addServer(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -762,9 +761,9 @@ public final class ServerImpl extends io.grpc.Server implements InternalInstrume
|
||||||
/**
|
/**
|
||||||
* Like {@link ServerCall#close(Status, Metadata)}, but thread-safe for internal use.
|
* Like {@link ServerCall#close(Status, Metadata)}, but thread-safe for internal use.
|
||||||
*/
|
*/
|
||||||
private void internalClose() {
|
private void internalClose(Throwable t) {
|
||||||
// TODO(ejona86): this is not thread-safe :)
|
// TODO(ejona86): this is not thread-safe :)
|
||||||
stream.close(Status.UNKNOWN, new Metadata());
|
stream.close(Status.UNKNOWN.withCause(t), new Metadata());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -785,10 +784,10 @@ public final class ServerImpl extends io.grpc.Server implements InternalInstrume
|
||||||
try {
|
try {
|
||||||
getListener().messagesAvailable(producer);
|
getListener().messagesAvailable(producer);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
internalClose();
|
internalClose(e);
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Error e) {
|
} catch (Error e) {
|
||||||
internalClose();
|
internalClose(e);
|
||||||
throw e;
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
PerfMark.stopTask("ServerCallListener(app).messagesAvailable", tag);
|
PerfMark.stopTask("ServerCallListener(app).messagesAvailable", tag);
|
||||||
|
|
@ -820,10 +819,10 @@ public final class ServerImpl extends io.grpc.Server implements InternalInstrume
|
||||||
try {
|
try {
|
||||||
getListener().halfClosed();
|
getListener().halfClosed();
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
internalClose();
|
internalClose(e);
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Error e) {
|
} catch (Error e) {
|
||||||
internalClose();
|
internalClose(e);
|
||||||
throw e;
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
PerfMark.stopTask("ServerCallListener(app).halfClosed", tag);
|
PerfMark.stopTask("ServerCallListener(app).halfClosed", tag);
|
||||||
|
|
@ -894,10 +893,10 @@ public final class ServerImpl extends io.grpc.Server implements InternalInstrume
|
||||||
try {
|
try {
|
||||||
getListener().onReady();
|
getListener().onReady();
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
internalClose();
|
internalClose(e);
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Error e) {
|
} catch (Error e) {
|
||||||
internalClose();
|
internalClose(e);
|
||||||
throw e;
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
PerfMark.stopTask("ServerCallListener(app).onReady", tag);
|
PerfMark.stopTask("ServerCallListener(app).onReady", tag);
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,30 @@
|
||||||
|
|
||||||
package io.grpc.inprocess;
|
package io.grpc.inprocess;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import io.grpc.CallOptions;
|
||||||
|
import io.grpc.ManagedChannel;
|
||||||
|
import io.grpc.Metadata;
|
||||||
|
import io.grpc.Server;
|
||||||
|
import io.grpc.ServerCall;
|
||||||
|
import io.grpc.ServerCallHandler;
|
||||||
|
import io.grpc.ServerServiceDefinition;
|
||||||
import io.grpc.ServerStreamTracer;
|
import io.grpc.ServerStreamTracer;
|
||||||
|
import io.grpc.Status;
|
||||||
|
import io.grpc.StatusRuntimeException;
|
||||||
import io.grpc.internal.AbstractTransportTest;
|
import io.grpc.internal.AbstractTransportTest;
|
||||||
import io.grpc.internal.GrpcUtil;
|
import io.grpc.internal.GrpcUtil;
|
||||||
import io.grpc.internal.InternalServer;
|
import io.grpc.internal.InternalServer;
|
||||||
import io.grpc.internal.ManagedClientTransport;
|
import io.grpc.internal.ManagedClientTransport;
|
||||||
|
import io.grpc.stub.ClientCalls;
|
||||||
|
import io.grpc.testing.GrpcCleanupRule;
|
||||||
|
import io.grpc.testing.TestMethodDescriptors;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.JUnit4;
|
import org.junit.runners.JUnit4;
|
||||||
|
|
@ -35,6 +51,9 @@ public class InProcessTransportTest extends AbstractTransportTest {
|
||||||
private static final String AUTHORITY = "a-testing-authority";
|
private static final String AUTHORITY = "a-testing-authority";
|
||||||
private static final String USER_AGENT = "a-testing-user-agent";
|
private static final String USER_AGENT = "a-testing-user-agent";
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final GrpcCleanupRule grpcCleanupRule = new GrpcCleanupRule();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<? extends InternalServer> newServer(
|
protected List<? extends InternalServer> newServer(
|
||||||
List<ServerStreamTracer.Factory> streamTracerFactories) {
|
List<ServerStreamTracer.Factory> streamTracerFactories) {
|
||||||
|
|
@ -59,7 +78,7 @@ public class InProcessTransportTest extends AbstractTransportTest {
|
||||||
protected ManagedClientTransport newClientTransport(InternalServer server) {
|
protected ManagedClientTransport newClientTransport(InternalServer server) {
|
||||||
return new InProcessTransport(
|
return new InProcessTransport(
|
||||||
TRANSPORT_NAME, GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE, testAuthority(server), USER_AGENT,
|
TRANSPORT_NAME, GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE, testAuthority(server), USER_AGENT,
|
||||||
eagAttrs());
|
eagAttrs(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -75,4 +94,42 @@ public class InProcessTransportTest extends AbstractTransportTest {
|
||||||
public void socketStats() throws Exception {
|
public void socketStats() throws Exception {
|
||||||
// test does not apply to in-process
|
// test does not apply to in-process
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void causeShouldBePropagatedWithStatus() throws Exception {
|
||||||
|
server = null;
|
||||||
|
String failingServerName = "server_foo";
|
||||||
|
String serviceFoo = "service_foo";
|
||||||
|
final Status s = Status.INTERNAL.withCause(new Throwable("failing server exception"));
|
||||||
|
ServerServiceDefinition definition = ServerServiceDefinition.builder(serviceFoo)
|
||||||
|
.addMethod(TestMethodDescriptors.voidMethod(), new ServerCallHandler<Void, Void>() {
|
||||||
|
@Override
|
||||||
|
public ServerCall.Listener<Void> startCall(
|
||||||
|
ServerCall<Void, Void> call, Metadata headers) {
|
||||||
|
call.close(s, new Metadata());
|
||||||
|
return new ServerCall.Listener<Void>() {};
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
Server failingServer = InProcessServerBuilder
|
||||||
|
.forName(failingServerName)
|
||||||
|
.addService(definition)
|
||||||
|
.directExecutor()
|
||||||
|
.build()
|
||||||
|
.start();
|
||||||
|
grpcCleanupRule.register(failingServer);
|
||||||
|
ManagedChannel channel = InProcessChannelBuilder
|
||||||
|
.forName(failingServerName)
|
||||||
|
.propagateCauseWithStatus(true)
|
||||||
|
.build();
|
||||||
|
grpcCleanupRule.register(channel);
|
||||||
|
try {
|
||||||
|
ClientCalls.blockingUnaryCall(channel, TestMethodDescriptors.voidMethod(),
|
||||||
|
CallOptions.DEFAULT, null);
|
||||||
|
fail("exception should have been thrown");
|
||||||
|
} catch (StatusRuntimeException e) {
|
||||||
|
// When propagateCauseWithStatus is true, the cause should be sent forward
|
||||||
|
assertEquals(s.getCause(), e.getCause());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ public abstract class AbstractTransportTest {
|
||||||
* {@code serverListener}, otherwise tearDown() can't wait for shutdown which can put following
|
* {@code serverListener}, otherwise tearDown() can't wait for shutdown which can put following
|
||||||
* tests in an indeterminate state.
|
* tests in an indeterminate state.
|
||||||
*/
|
*/
|
||||||
private InternalServer server;
|
protected InternalServer server;
|
||||||
private ServerTransport serverTransport;
|
private ServerTransport serverTransport;
|
||||||
private ManagedClientTransport client;
|
private ManagedClientTransport client;
|
||||||
private MethodDescriptor<String, String> methodDescriptor =
|
private MethodDescriptor<String, String> methodDescriptor =
|
||||||
|
|
@ -1058,9 +1058,7 @@ public abstract class AbstractTransportTest {
|
||||||
Metadata clientStreamTrailers =
|
Metadata clientStreamTrailers =
|
||||||
clientStreamListener.trailers.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
clientStreamListener.trailers.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||||
assertNotNull(clientStreamTrailers);
|
assertNotNull(clientStreamTrailers);
|
||||||
assertEquals(status.getCode(), clientStreamStatus.getCode());
|
checkClientStatus(status, clientStreamStatus);
|
||||||
assertEquals("Hello. Goodbye.", clientStreamStatus.getDescription());
|
|
||||||
assertNull(clientStreamStatus.getCause());
|
|
||||||
assertTrue(clientStreamTracer1.getOutboundHeaders());
|
assertTrue(clientStreamTracer1.getOutboundHeaders());
|
||||||
assertTrue(clientStreamTracer1.getInboundHeaders());
|
assertTrue(clientStreamTracer1.getInboundHeaders());
|
||||||
assertSame(clientStreamTrailers, clientStreamTracer1.getInboundTrailers());
|
assertSame(clientStreamTrailers, clientStreamTracer1.getInboundTrailers());
|
||||||
|
|
@ -1097,10 +1095,7 @@ public abstract class AbstractTransportTest {
|
||||||
Status clientStreamStatus = clientStreamListener.status.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
Status clientStreamStatus = clientStreamListener.status.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||||
Metadata clientStreamTrailers =
|
Metadata clientStreamTrailers =
|
||||||
clientStreamListener.trailers.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
clientStreamListener.trailers.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||||
assertEquals(status.getCode(), clientStreamStatus.getCode());
|
checkClientStatus(status, clientStreamStatus);
|
||||||
assertEquals("Hellogoodbye", clientStreamStatus.getDescription());
|
|
||||||
// Cause should not be transmitted to the client.
|
|
||||||
assertNull(clientStreamStatus.getCause());
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
Lists.newArrayList(trailers.getAll(asciiKey)),
|
Lists.newArrayList(trailers.getAll(asciiKey)),
|
||||||
Lists.newArrayList(clientStreamTrailers.getAll(asciiKey)));
|
Lists.newArrayList(clientStreamTrailers.getAll(asciiKey)));
|
||||||
|
|
@ -1138,9 +1133,7 @@ public abstract class AbstractTransportTest {
|
||||||
Metadata clientStreamTrailers =
|
Metadata clientStreamTrailers =
|
||||||
clientStreamListener.trailers.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
clientStreamListener.trailers.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||||
assertNotNull(clientStreamTrailers);
|
assertNotNull(clientStreamTrailers);
|
||||||
assertEquals(status.getCode(), clientStreamStatus.getCode());
|
checkClientStatus(status, clientStreamStatus);
|
||||||
assertEquals(status.getDescription(), clientStreamStatus.getDescription());
|
|
||||||
assertNull(clientStreamStatus.getCause());
|
|
||||||
assertTrue(clientStreamTracer1.getOutboundHeaders());
|
assertTrue(clientStreamTracer1.getOutboundHeaders());
|
||||||
assertSame(clientStreamTrailers, clientStreamTracer1.getInboundTrailers());
|
assertSame(clientStreamTrailers, clientStreamTracer1.getInboundTrailers());
|
||||||
assertSame(clientStreamStatus, clientStreamTracer1.getStatus());
|
assertSame(clientStreamStatus, clientStreamTracer1.getStatus());
|
||||||
|
|
@ -1188,9 +1181,7 @@ public abstract class AbstractTransportTest {
|
||||||
Metadata clientStreamTrailers =
|
Metadata clientStreamTrailers =
|
||||||
clientStreamListener.trailers.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
clientStreamListener.trailers.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||||
assertNotNull(clientStreamTrailers);
|
assertNotNull(clientStreamTrailers);
|
||||||
assertEquals(status.getCode(), clientStreamStatus.getCode());
|
checkClientStatus(status, clientStreamStatus);
|
||||||
assertEquals(status.getDescription(), clientStreamStatus.getDescription());
|
|
||||||
assertNull(clientStreamStatus.getCause());
|
|
||||||
assertTrue(clientStreamTracer1.getOutboundHeaders());
|
assertTrue(clientStreamTracer1.getOutboundHeaders());
|
||||||
assertSame(clientStreamTrailers, clientStreamTracer1.getInboundTrailers());
|
assertSame(clientStreamTrailers, clientStreamTracer1.getInboundTrailers());
|
||||||
assertSame(clientStreamStatus, clientStreamTracer1.getStatus());
|
assertSame(clientStreamStatus, clientStreamTracer1.getStatus());
|
||||||
|
|
@ -1219,7 +1210,7 @@ public abstract class AbstractTransportTest {
|
||||||
assertNotNull(clientStreamListener.trailers.get(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
assertNotNull(clientStreamListener.trailers.get(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||||
Status serverStatus = serverStreamListener.status.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
Status serverStatus = serverStreamListener.status.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||||
assertNotEquals(Status.Code.OK, serverStatus.getCode());
|
assertNotEquals(Status.Code.OK, serverStatus.getCode());
|
||||||
// Cause should not be transmitted between client and server
|
// Cause should not be transmitted between client and server by default
|
||||||
assertNull(serverStatus.getCause());
|
assertNull(serverStatus.getCause());
|
||||||
|
|
||||||
clientStream.cancel(status);
|
clientStream.cancel(status);
|
||||||
|
|
@ -2072,6 +2063,16 @@ public abstract class AbstractTransportTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies that the client status is as expected. By default, the code and description should
|
||||||
|
* be present, and the cause should be stripped away.
|
||||||
|
*/
|
||||||
|
private void checkClientStatus(Status expectedStatus, Status clientStreamStatus) {
|
||||||
|
assertEquals(expectedStatus.getCode(), clientStreamStatus.getCode());
|
||||||
|
assertEquals(expectedStatus.getDescription(), clientStreamStatus.getDescription());
|
||||||
|
assertNull(clientStreamStatus.getCause());
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean waitForFuture(Future<?> future, long timeout, TimeUnit unit)
|
private static boolean waitForFuture(Future<?> future, long timeout, TimeUnit unit)
|
||||||
throws InterruptedException {
|
throws InterruptedException {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -1441,8 +1441,9 @@ public class ServerImplTest {
|
||||||
|
|
||||||
private void ensureServerStateNotLeaked() {
|
private void ensureServerStateNotLeaked() {
|
||||||
verify(stream).close(statusCaptor.capture(), metadataCaptor.capture());
|
verify(stream).close(statusCaptor.capture(), metadataCaptor.capture());
|
||||||
assertEquals(Status.UNKNOWN, statusCaptor.getValue());
|
assertEquals(Status.UNKNOWN.getCode(), statusCaptor.getValue().getCode());
|
||||||
assertNull(statusCaptor.getValue().getCause());
|
// Used in InProcessTransport when set to include the cause with the status
|
||||||
|
assertNotNull(statusCaptor.getValue().getCause());
|
||||||
assertTrue(metadataCaptor.getValue().keys().isEmpty());
|
assertTrue(metadataCaptor.getValue().keys().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue