mirror of https://github.com/grpc/grpc-java.git
parent
255643bed9
commit
071942dc3b
|
|
@ -388,6 +388,12 @@ final class InProcessTransport implements ServerTransport, ConnectionClientTrans
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close(Status status, Metadata trailers) {
|
public void close(Status status, Metadata trailers) {
|
||||||
|
// clientStream.serverClosed must happen before clientStreamListener.closed, otherwise
|
||||||
|
// clientStreamListener.closed can trigger clientStream.cancel (see code in
|
||||||
|
// ClientCalls.blockingUnaryCall), which may race with clientStream.serverClosed as both are
|
||||||
|
// calling internalCancel().
|
||||||
|
clientStream.serverClosed(Status.OK, status);
|
||||||
|
|
||||||
Status clientStatus = stripCause(status);
|
Status clientStatus = stripCause(status);
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (closed) {
|
if (closed) {
|
||||||
|
|
@ -403,7 +409,6 @@ final class InProcessTransport implements ServerTransport, ConnectionClientTrans
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clientStream.serverClosed(Status.OK, status);
|
|
||||||
streamClosed();
|
streamClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -947,6 +947,45 @@ public abstract class AbstractTransportTest {
|
||||||
assertSame(status, serverStreamTracer1.getStatus());
|
assertSame(status, serverStreamTracer1.getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void earlyServerClose_serverFailure_withClientCancelOnListenerClosed() throws Exception {
|
||||||
|
server.start(serverListener);
|
||||||
|
client = newClientTransport(server);
|
||||||
|
runIfNotNull(client.start(mockClientTransportListener));
|
||||||
|
MockServerTransportListener serverTransportListener
|
||||||
|
= serverListener.takeListenerOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||||
|
serverTransport = serverTransportListener.transport;
|
||||||
|
|
||||||
|
final ClientStream clientStream =
|
||||||
|
client.newStream(methodDescriptor, new Metadata(), callOptions);
|
||||||
|
ClientStreamListenerBase clientStreamListener = new ClientStreamListenerBase() {
|
||||||
|
@Override
|
||||||
|
public void closed(Status status, Metadata trailers) {
|
||||||
|
super.closed(status, trailers);
|
||||||
|
// This simulates the blocking calls which can trigger clientStream.cancel().
|
||||||
|
clientStream.cancel(Status.CANCELLED.withCause(status.asRuntimeException()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
clientStream.start(clientStreamListener);
|
||||||
|
StreamCreation serverStreamCreation
|
||||||
|
= serverTransportListener.takeStreamOrFail(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||||
|
ServerStream serverStream = serverStreamCreation.stream;
|
||||||
|
ServerStreamListenerBase serverStreamListener = serverStreamCreation.listener;
|
||||||
|
|
||||||
|
Status strippedStatus = Status.INTERNAL.withDescription("I'm not listening");
|
||||||
|
Status status = strippedStatus.withCause(new Exception());
|
||||||
|
serverStream.close(status, new Metadata());
|
||||||
|
assertCodeEquals(Status.OK, serverStreamListener.status.get(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||||
|
Status clientStreamStatus = clientStreamListener.status.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||||
|
assertNotNull(clientStreamListener.trailers.get(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||||
|
assertEquals(status.getCode(), clientStreamStatus.getCode());
|
||||||
|
assertEquals(status.getDescription(), clientStreamStatus.getDescription());
|
||||||
|
assertNull(clientStreamStatus.getCause());
|
||||||
|
assertTrue(clientStreamTracer1.getOutboundHeaders());
|
||||||
|
assertSame(clientStreamStatus, clientStreamTracer1.getStatus());
|
||||||
|
assertSame(status, serverStreamTracer1.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void clientCancel() throws Exception {
|
public void clientCancel() throws Exception {
|
||||||
server.start(serverListener);
|
server.start(serverListener);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue