use of io.grpc.ServerCall in project grpc-java by grpc.
the class ServerCallsTest method cannotSetOnCancelHandlerAfterServiceInvocation.
@Test
public void cannotSetOnCancelHandlerAfterServiceInvocation() throws Exception {
final AtomicReference<ServerCallStreamObserver<Integer>> callObserver = new AtomicReference<ServerCallStreamObserver<Integer>>();
ServerCallHandler<Integer, Integer> callHandler = ServerCalls.asyncBidiStreamingCall(new ServerCalls.BidiStreamingMethod<Integer, Integer>() {
@Override
public StreamObserver<Integer> invoke(StreamObserver<Integer> responseObserver) {
callObserver.set((ServerCallStreamObserver<Integer>) responseObserver);
return new ServerCalls.NoopStreamObserver<Integer>();
}
});
ServerCall.Listener<Integer> callListener = callHandler.startCall(serverCall, new Metadata());
callListener.onMessage(1);
try {
callObserver.get().setOnCancelHandler(new Runnable() {
@Override
public void run() {
}
});
fail("Cannot set onCancel handler after service invocation");
} catch (IllegalStateException expected) {
// Expected
}
}
use of io.grpc.ServerCall in project grpc-java by grpc.
the class ServerCallsTest method cannotDisableAutoFlowControlAfterServiceInvocation.
@Test
public void cannotDisableAutoFlowControlAfterServiceInvocation() throws Exception {
final AtomicReference<ServerCallStreamObserver<Integer>> callObserver = new AtomicReference<ServerCallStreamObserver<Integer>>();
ServerCallHandler<Integer, Integer> callHandler = ServerCalls.asyncBidiStreamingCall(new ServerCalls.BidiStreamingMethod<Integer, Integer>() {
@Override
public StreamObserver<Integer> invoke(StreamObserver<Integer> responseObserver) {
callObserver.set((ServerCallStreamObserver<Integer>) responseObserver);
return new ServerCalls.NoopStreamObserver<Integer>();
}
});
ServerCall.Listener<Integer> callListener = callHandler.startCall(serverCall, new Metadata());
callListener.onMessage(1);
try {
callObserver.get().disableAutoInboundFlowControl();
fail("Cannot set onCancel handler after service invocation");
} catch (IllegalStateException expected) {
// Expected
}
}
use of io.grpc.ServerCall in project grpc-java by grpc.
the class ServerCalls method asyncUnaryRequestCall.
/**
* Creates a {@code ServerCallHandler} for a unary request call method of the service.
*
* @param method an adaptor to the actual method on the service implementation.
*/
private static <ReqT, RespT> ServerCallHandler<ReqT, RespT> asyncUnaryRequestCall(final UnaryRequestMethod<ReqT, RespT> method) {
return new ServerCallHandler<ReqT, RespT>() {
@Override
public ServerCall.Listener<ReqT> startCall(final ServerCall<ReqT, RespT> call, Metadata headers) {
final ServerCallStreamObserverImpl<ReqT, RespT> responseObserver = new ServerCallStreamObserverImpl<ReqT, RespT>(call);
// We expect only 1 request, but we ask for 2 requests here so that if a misbehaving client
// sends more than 1 requests, ServerCall will catch it. Note that disabling auto
// inbound flow control has no effect on unary calls.
call.request(2);
return new EmptyServerCallListener<ReqT>() {
ReqT request;
@Override
public void onMessage(ReqT request) {
// We delay calling method.invoke() until onHalfClose() to make sure the client
// half-closes.
this.request = request;
}
@Override
public void onHalfClose() {
if (request != null) {
method.invoke(request, responseObserver);
responseObserver.freeze();
if (call.isReady()) {
// Since we are calling invoke in halfClose we have missed the onReady
// event from the transport so recover it here.
onReady();
}
} else {
call.close(Status.INTERNAL.withDescription("Half-closed without a request"), new Metadata());
}
}
@Override
public void onCancel() {
responseObserver.cancelled = true;
if (responseObserver.onCancelHandler != null) {
responseObserver.onCancelHandler.run();
}
}
@Override
public void onReady() {
if (responseObserver.onReadyHandler != null) {
responseObserver.onReadyHandler.run();
}
}
};
}
};
}
use of io.grpc.ServerCall in project grpc-java by grpc.
the class ServerImplTest method testCallContextIsBoundInListenerCallbacks.
@Test
public void testCallContextIsBoundInListenerCallbacks() throws Exception {
createAndStartServer(NO_FILTERS);
MethodDescriptor<String, Integer> method = MethodDescriptor.<String, Integer>newBuilder().setType(MethodDescriptor.MethodType.UNKNOWN).setFullMethodName("Waiter/serve").setRequestMarshaller(STRING_MARSHALLER).setResponseMarshaller(INTEGER_MARSHALLER).build();
final AtomicBoolean onReadyCalled = new AtomicBoolean(false);
final AtomicBoolean onMessageCalled = new AtomicBoolean(false);
final AtomicBoolean onHalfCloseCalled = new AtomicBoolean(false);
final AtomicBoolean onCancelCalled = new AtomicBoolean(false);
mutableFallbackRegistry.addService(ServerServiceDefinition.builder(new ServiceDescriptor("Waiter", method)).addMethod(method, new ServerCallHandler<String, Integer>() {
@Override
public ServerCall.Listener<String> startCall(ServerCall<String, Integer> call, Metadata headers) {
// Check that the current context is a descendant of SERVER_CONTEXT
final Context initial = Context.current();
assertEquals("yes", SERVER_ONLY.get(initial));
assertNotSame(SERVER_CONTEXT, initial);
assertFalse(initial.isCancelled());
return new ServerCall.Listener<String>() {
@Override
public void onReady() {
checkContext();
onReadyCalled.set(true);
}
@Override
public void onMessage(String message) {
checkContext();
onMessageCalled.set(true);
}
@Override
public void onHalfClose() {
checkContext();
onHalfCloseCalled.set(true);
}
@Override
public void onCancel() {
checkContext();
onCancelCalled.set(true);
}
@Override
public void onComplete() {
checkContext();
}
private void checkContext() {
// Check that the bound context is the same as the initial one.
assertSame(initial, Context.current());
}
};
}
}).build());
ServerTransportListener transportListener = transportServer.registerNewServerTransport(new SimpleServerTransport());
Metadata requestHeaders = new Metadata();
StatsTraceContext statsTraceCtx = transportListener.methodDetermined("Waiter/serve", requestHeaders);
assertNotNull(statsTraceCtx);
when(stream.statsTraceContext()).thenReturn(statsTraceCtx);
transportListener.streamCreated(stream, "Waiter/serve", requestHeaders);
verify(stream).setListener(streamListenerCaptor.capture());
ServerStreamListener streamListener = streamListenerCaptor.getValue();
assertNotNull(streamListener);
streamListener.onReady();
assertEquals(1, executor.runDueTasks());
assertTrue(onReadyCalled.get());
streamListener.messageRead(new ByteArrayInputStream(new byte[0]));
assertEquals(1, executor.runDueTasks());
assertTrue(onMessageCalled.get());
streamListener.halfClosed();
assertEquals(1, executor.runDueTasks());
assertTrue(onHalfCloseCalled.get());
streamListener.closed(Status.CANCELLED);
assertEquals(1, executor.runDueTasks());
assertTrue(onCancelCalled.get());
// Close should never be called if asserts in listener pass.
verify(stream, times(0)).close(isA(Status.class), isNotNull(Metadata.class));
}
use of io.grpc.ServerCall in project grpc-java by grpc.
the class ServerImplTest method basicExchangeSuccessful.
@Test
public void basicExchangeSuccessful() throws Exception {
createAndStartServer(NO_FILTERS);
final Metadata.Key<String> metadataKey = Metadata.Key.of("inception", Metadata.ASCII_STRING_MARSHALLER);
final Metadata.Key<StatsContext> statsHeaderKey = StatsTraceContext.createStatsHeader(statsCtxFactory);
final AtomicReference<ServerCall<String, Integer>> callReference = new AtomicReference<ServerCall<String, Integer>>();
MethodDescriptor<String, Integer> method = MethodDescriptor.<String, Integer>newBuilder().setType(MethodDescriptor.MethodType.UNKNOWN).setFullMethodName("Waiter/serve").setRequestMarshaller(STRING_MARSHALLER).setResponseMarshaller(INTEGER_MARSHALLER).build();
mutableFallbackRegistry.addService(ServerServiceDefinition.builder(new ServiceDescriptor("Waiter", method)).addMethod(method, new ServerCallHandler<String, Integer>() {
@Override
public ServerCall.Listener<String> startCall(ServerCall<String, Integer> call, Metadata headers) {
assertEquals("Waiter/serve", call.getMethodDescriptor().getFullMethodName());
assertNotNull(call);
assertNotNull(headers);
assertEquals("value", headers.get(metadataKey));
callReference.set(call);
return callListener;
}
}).build());
ServerTransportListener transportListener = transportServer.registerNewServerTransport(new SimpleServerTransport());
Metadata requestHeaders = new Metadata();
requestHeaders.put(metadataKey, "value");
StatsContext statsContextOnClient = statsCtxFactory.getDefault().with(StatsTestUtils.EXTRA_TAG, TagValue.create("extraTagValue"));
requestHeaders.put(statsHeaderKey, statsContextOnClient);
StatsTraceContext statsTraceCtx = transportListener.methodDetermined("Waiter/serve", requestHeaders);
assertNotNull(statsTraceCtx);
when(stream.statsTraceContext()).thenReturn(statsTraceCtx);
transportListener.streamCreated(stream, "Waiter/serve", requestHeaders);
verify(stream).setListener(streamListenerCaptor.capture());
ServerStreamListener streamListener = streamListenerCaptor.getValue();
assertNotNull(streamListener);
verify(stream, atLeast(1)).statsTraceContext();
assertEquals(1, executor.runDueTasks());
ServerCall<String, Integer> call = callReference.get();
assertNotNull(call);
verify(stream).getAuthority();
String order = "Lots of pizza, please";
streamListener.messageRead(STRING_MARSHALLER.stream(order));
assertEquals(1, executor.runDueTasks());
verify(callListener).onMessage(order);
Metadata responseHeaders = new Metadata();
responseHeaders.put(metadataKey, "response value");
call.sendHeaders(responseHeaders);
verify(stream).writeHeaders(responseHeaders);
verify(stream).setCompressor(isA(Compressor.class));
call.sendMessage(314);
ArgumentCaptor<InputStream> inputCaptor = ArgumentCaptor.forClass(InputStream.class);
verify(stream).writeMessage(inputCaptor.capture());
verify(stream).flush();
assertEquals(314, INTEGER_MARSHALLER.parse(inputCaptor.getValue()).intValue());
// All full; no dessert.
streamListener.halfClosed();
assertEquals(1, executor.runDueTasks());
verify(callListener).onHalfClose();
call.sendMessage(50);
verify(stream, times(2)).writeMessage(inputCaptor.capture());
verify(stream, times(2)).flush();
assertEquals(50, INTEGER_MARSHALLER.parse(inputCaptor.getValue()).intValue());
Metadata trailers = new Metadata();
trailers.put(metadataKey, "another value");
Status status = Status.OK.withDescription("A okay");
call.close(status, trailers);
verify(stream).close(status, trailers);
streamListener.closed(Status.OK);
assertEquals(1, executor.runDueTasks());
verify(callListener).onComplete();
verify(stream, atLeast(1)).statsTraceContext();
verifyNoMoreInteractions(stream);
verifyNoMoreInteractions(callListener);
// Check stats
StatsTestUtils.MetricsRecord record = statsCtxFactory.pollRecord();
assertNotNull(record);
TagValue methodTag = record.tags.get(RpcConstants.RPC_SERVER_METHOD);
assertNotNull(methodTag);
assertEquals("Waiter/serve", methodTag.toString());
TagValue statusTag = record.tags.get(RpcConstants.RPC_STATUS);
assertNotNull(statusTag);
assertEquals(Status.Code.OK.toString(), statusTag.toString());
TagValue extraTag = record.tags.get(StatsTestUtils.EXTRA_TAG);
assertNotNull(extraTag);
assertEquals("extraTagValue", extraTag.toString());
assertNull(record.getMetric(RpcConstants.RPC_CLIENT_REQUEST_BYTES));
assertNull(record.getMetric(RpcConstants.RPC_CLIENT_RESPONSE_BYTES));
assertNull(record.getMetric(RpcConstants.RPC_CLIENT_UNCOMPRESSED_REQUEST_BYTES));
assertNull(record.getMetric(RpcConstants.RPC_CLIENT_UNCOMPRESSED_RESPONSE_BYTES));
// The test doesn't invoke MessageFramer and MessageDeframer which keep the sizes.
// Thus the sizes reported to stats would be zero.
assertEquals(0, record.getMetricAsLongOrFail(RpcConstants.RPC_SERVER_REQUEST_BYTES));
assertEquals(0, record.getMetricAsLongOrFail(RpcConstants.RPC_SERVER_RESPONSE_BYTES));
assertEquals(0, record.getMetricAsLongOrFail(RpcConstants.RPC_SERVER_UNCOMPRESSED_REQUEST_BYTES));
assertEquals(0, record.getMetricAsLongOrFail(RpcConstants.RPC_SERVER_UNCOMPRESSED_RESPONSE_BYTES));
}
Aggregations