@Override public RpcResponse serve(ServiceRequestContext ctx, RpcRequest call) throws Exception { final int colonPos = call.method().indexOf(':'); final String method; final String serviceName; if (colonPos < 0) { serviceName = ""; method = call.method(); } else { serviceName = call.method().substring(0, colonPos); method = call.method().substring(colonPos + 1); } // Ensure that such a service exists. final ThriftServiceEntry e = entries.get(serviceName); if (e != null) { // Ensure that such a method exists. final ThriftFunction f = e.metadata.function(method); if (f != null) { final DefaultRpcResponse reply = new DefaultRpcResponse(); invoke(ctx, e.implementation, f, call.params(), reply); return reply; } } return new DefaultRpcResponse(new TApplicationException( TApplicationException.UNKNOWN_METHOD, "unknown method: " + call.method())); }
private void exportRpcRequest(Map<String, String> out, RequestLog log) { if (!log.isAvailable(RequestLogAvailability.REQUEST_CONTENT)) { return; } final Object requestContent = log.requestContent(); if (requestContent instanceof RpcRequest) { final RpcRequest rpcReq = (RpcRequest) requestContent; if (builtIns.contains(REQ_RPC_METHOD)) { out.put(REQ_RPC_METHOD.mdcKey, rpcReq.method()); } if (builtIns.contains(REQ_RPC_PARAMS)) { out.put(REQ_RPC_PARAMS.mdcKey, String.valueOf(rpcReq.params())); } } }
@Test public void compressedClient_compressedEndpoint() throws Exception { assertThat(blockingClient.staticUnaryCallSetsMessageCompression(REQUEST_MESSAGE)) .isEqualTo(RESPONSE_MESSAGE); checkRequestLog((rpcReq, rpcRes, grpcStatus) -> { assertThat(rpcReq.method()).isEqualTo( "armeria.grpc.testing.UnitTestService/StaticUnaryCallSetsMessageCompression"); assertThat(rpcReq.params()).containsExactly(REQUEST_MESSAGE); assertThat(rpcRes.get()).isEqualTo(RESPONSE_MESSAGE); }); }
@Test public void unary_normal() throws Exception { assertThat(blockingClient.staticUnaryCall(REQUEST_MESSAGE)).isEqualTo(RESPONSE_MESSAGE); // Confirm gRPC paths are cached despite using serviceUnder assertThat(PathAndQuery.cachedPaths()) .contains("/armeria.grpc.testing.UnitTestService/StaticUnaryCall"); checkRequestLog((rpcReq, rpcRes, grpcStatus) -> { assertThat(rpcReq.method()).isEqualTo("armeria.grpc.testing.UnitTestService/StaticUnaryCall"); assertThat(rpcReq.params()).containsExactly(REQUEST_MESSAGE); assertThat(rpcRes.get()).isEqualTo(RESPONSE_MESSAGE); }); }
private static void verifyOneWayInvocation(Class<?> expectedServiceType, String expectedParam) { await().untilAsserted(() -> { final RequestLog log = requestLogs.poll(); assertThat(log).isNotNull(); final RpcRequest req = (RpcRequest) log.requestContent(); final RpcResponse res = (RpcResponse) log.responseContent(); assertThat(req).isNotNull(); assertThat(req.serviceType()).isSameAs(expectedServiceType); assertThat(req.method()).isEqualTo("hello"); assertThat(req.params()).containsExactly(expectedParam); assertThat((Object) res).isNotNull(); assertThat(res.get()).isNull(); }); }
@Test public void error_thrown_unary() throws Exception { final StatusRuntimeException t = (StatusRuntimeException) catchThrowable( () -> blockingClient.unaryThrowsError(REQUEST_MESSAGE)); assertThat(t.getStatus().getCode()).isEqualTo(Code.ABORTED); assertThat(t.getStatus().getDescription()).isEqualTo("call aborted"); checkRequestLog((rpcReq, rpcRes, grpcStatus) -> { assertThat(rpcReq.method()).isEqualTo("armeria.grpc.testing.UnitTestService/UnaryThrowsError"); assertThat(rpcReq.params()).containsExactly(REQUEST_MESSAGE); assertThat(grpcStatus).isNotNull(); assertThat(grpcStatus.getCode()).isEqualTo(Code.ABORTED); assertThat(grpcStatus.getDescription()).isEqualTo("call aborted"); }); }
@Test public void error_withMessage() throws Exception { final StatusRuntimeException t = (StatusRuntimeException) catchThrowable( () -> blockingClient.errorWithMessage(REQUEST_MESSAGE)); assertThat(t.getStatus().getCode()).isEqualTo(Code.ABORTED); assertThat(t.getStatus().getDescription()).isEqualTo("aborted call"); checkRequestLog((rpcReq, rpcRes, grpcStatus) -> { assertThat(rpcReq.method()).isEqualTo("armeria.grpc.testing.UnitTestService/ErrorWithMessage"); assertThat(rpcReq.params()).containsExactly(REQUEST_MESSAGE); assertThat(grpcStatus).isNotNull(); assertThat(grpcStatus.getCode()).isEqualTo(Code.ABORTED); assertThat(grpcStatus.getDescription()).isEqualTo("aborted call"); }); }
@Test public void streamedOutput_normal() throws Exception { final StreamRecorder<SimpleResponse> recorder = StreamRecorder.create(); streamingClient.staticStreamedOutputCall(REQUEST_MESSAGE, recorder); recorder.awaitCompletion(); assertThat(recorder.getValues()).containsExactly(RESPONSE_MESSAGE, RESPONSE_MESSAGE); checkRequestLog((rpcReq, rpcRes, grpcStatus) -> { assertThat(rpcReq.method()).isEqualTo( "armeria.grpc.testing.UnitTestService/StaticStreamedOutputCall"); assertThat(rpcReq.params()).containsExactly(REQUEST_MESSAGE); assertThat(rpcRes.get()).isEqualTo(RESPONSE_MESSAGE); }); }
@Test public void error_noMessage() throws Exception { final StatusRuntimeException t = (StatusRuntimeException) catchThrowable( () -> blockingClient.errorNoMessage(REQUEST_MESSAGE)); assertThat(t.getStatus().getCode()).isEqualTo(Code.ABORTED); assertThat(t.getStatus().getDescription()).isNull(); checkRequestLog((rpcReq, rpcRes, grpcStatus) -> { assertThat(rpcReq.method()).isEqualTo("armeria.grpc.testing.UnitTestService/ErrorNoMessage"); assertThat(rpcReq.params()).containsExactly(REQUEST_MESSAGE); assertThat(grpcStatus).isNotNull(); assertThat(grpcStatus.getCode()).isEqualTo(Code.ABORTED); assertThat(grpcStatus.getDescription()).isNull(); }); }
private List<Tag> buildTags(RequestLog log) { final RequestContext ctx = log.context(); final Object requestContent = log.requestContent(); String methodName = null; if (requestContent instanceof RpcRequest) { methodName = ((RpcRequest) requestContent).method(); } if (methodName == null) { final HttpHeaders requestHeaders = log.requestHeaders(); final HttpMethod httpMethod = requestHeaders.method(); if (httpMethod != null) { methodName = httpMethod.name(); } } if (methodName == null) { methodName = MoreObjects.firstNonNull(log.method().name(), "__UNKNOWN_METHOD__"); } final List<Tag> tags = new ArrayList<>(4); // method, hostNamePattern, pathMapping, status tags.add(Tag.of("method", methodName)); if (ctx instanceof ServiceRequestContext) { final ServiceRequestContext sCtx = (ServiceRequestContext) ctx; tags.add(Tag.of("hostnamePattern", sCtx.virtualHost().hostnamePattern())); tags.add(Tag.of("pathMapping", sCtx.pathMapping().meterTag())); } return tags; } };
@Test public void error_thrown_streamMessage() throws Exception { final StreamRecorder<SimpleResponse> response = StreamRecorder.create(); final StreamObserver<SimpleRequest> request = streamingClient.streamThrowsError(response); request.onNext(REQUEST_MESSAGE); response.awaitCompletion(); final StatusRuntimeException t = (StatusRuntimeException) response.getError(); assertThat(t.getStatus().getCode()).isEqualTo(Code.ABORTED); assertThat(t.getStatus().getDescription()).isEqualTo("bad streaming message"); checkRequestLog((rpcReq, rpcRes, grpcStatus) -> { assertThat(rpcReq.method()).isEqualTo("armeria.grpc.testing.UnitTestService/StreamThrowsError"); assertThat(rpcReq.params()).containsExactly(REQUEST_MESSAGE); assertThat(grpcStatus).isNotNull(); assertThat(grpcStatus.getCode()).isEqualTo(Code.ABORTED); assertThat(grpcStatus.getDescription()).isEqualTo("bad streaming message"); }); }
@Test public void json() throws Exception { final AtomicReference<HttpHeaders> requestHeaders = new AtomicReference<>(); final UnitTestServiceBlockingStub jsonStub = new ClientBuilder(server.httpUri(GrpcSerializationFormats.JSON, "/")) .decorator(client -> new SimpleDecoratingClient<HttpRequest, HttpResponse>(client) { @Override public HttpResponse execute(ClientRequestContext ctx, HttpRequest req) throws Exception { requestHeaders.set(req.headers()); return delegate().execute(ctx, req); } }) .build(UnitTestServiceBlockingStub.class); final SimpleResponse response = jsonStub.staticUnaryCall(REQUEST_MESSAGE); assertThat(response).isEqualTo(RESPONSE_MESSAGE); assertThat(requestHeaders.get().get(HttpHeaderNames.CONTENT_TYPE)).isEqualTo("application/grpc+json"); checkRequestLog((rpcReq, rpcRes, grpcStatus) -> { assertThat(rpcReq.method()).isEqualTo("armeria.grpc.testing.UnitTestService/StaticUnaryCall"); assertThat(rpcReq.params()).containsExactly(REQUEST_MESSAGE); assertThat(rpcRes.get()).isEqualTo(RESPONSE_MESSAGE); }); }
@Test public void requestContextSet() throws Exception { final StreamRecorder<SimpleResponse> response = StreamRecorder.create(); final StreamObserver<SimpleRequest> request = streamingClient.checkRequestContext(response); request.onNext(REQUEST_MESSAGE); request.onNext(REQUEST_MESSAGE); request.onNext(REQUEST_MESSAGE); request.onCompleted(); response.awaitCompletion(); final SimpleResponse expectedResponse = SimpleResponse.newBuilder() .setPayload(Payload.newBuilder() .setBody(ByteString.copyFromUtf8("3"))) .build(); assertThat(response.getValues()).containsExactly(expectedResponse); checkRequestLog((rpcReq, rpcRes, grpcStatus) -> { assertThat(rpcReq.method()).isEqualTo("armeria.grpc.testing.UnitTestService/CheckRequestContext"); assertThat(rpcReq.params()).containsExactly(REQUEST_MESSAGE); assertThat(rpcRes.get()).isEqualTo(expectedResponse); }); }
@Test public void uncompressedClient_compressedEndpoint() throws Exception { final ManagedChannel nonDecompressingChannel = ManagedChannelBuilder.forAddress("127.0.0.1", server.httpPort()) .decompressorRegistry( DecompressorRegistry.emptyInstance() .with(Codec.Identity.NONE, false)) .usePlaintext() .build(); final UnitTestServiceBlockingStub client = UnitTestServiceGrpc.newBlockingStub(nonDecompressingChannel); assertThat(client.staticUnaryCallSetsMessageCompression(REQUEST_MESSAGE)) .isEqualTo(RESPONSE_MESSAGE); nonDecompressingChannel.shutdownNow(); checkRequestLog((rpcReq, rpcRes, grpcStatus) -> { assertThat(rpcReq.method()).isEqualTo( "armeria.grpc.testing.UnitTestService/StaticUnaryCallSetsMessageCompression"); assertThat(rpcReq.params()).containsExactly(REQUEST_MESSAGE); assertThat(rpcRes.get()).isEqualTo(RESPONSE_MESSAGE); }); }
@Test public void unframed() throws Exception { final HttpClient client = HttpClient.of(server.httpUri("/")); final AggregatedHttpMessage response = client.execute( HttpHeaders.of(HttpMethod.POST, UnitTestServiceGrpc.getStaticUnaryCallMethod().getFullMethodName()) .set(HttpHeaderNames.CONTENT_TYPE, "application/protobuf"), REQUEST_MESSAGE.toByteArray()).aggregate().get(); final SimpleResponse message = SimpleResponse.parseFrom(response.content().array()); assertThat(message).isEqualTo(RESPONSE_MESSAGE); assertThat(response.headers().getInt(HttpHeaderNames.CONTENT_LENGTH)) .isEqualTo(response.content().length()); checkRequestLog((rpcReq, rpcRes, grpcStatus) -> { assertThat(rpcReq.method()).isEqualTo("armeria.grpc.testing.UnitTestService/StaticUnaryCall"); assertThat(rpcReq.params()).containsExactly(REQUEST_MESSAGE); assertThat(rpcRes.get()).isEqualTo(RESPONSE_MESSAGE); }); }
@Override protected void configure(ServerBuilder sb) throws Exception { sb.service( "/", THttpService.of(ImmutableMap.of("", (Iface) name -> "none:" + name, "foo", name -> "foo:" + name, "bar", name -> "bar:" + name)) .decorate((delegate, ctx, req) -> { ctx.log().addListener(log -> { final RpcRequest call = (RpcRequest) log.requestContent(); if (call != null) { methodNames.add(call.method()); } }, RequestLogAvailability.REQUEST_CONTENT); return delegate.serve(ctx, req); })); } };
@Test public void unframed_acceptEncoding() throws Exception { final HttpClient client = HttpClient.of(server.httpUri("/")); final AggregatedHttpMessage response = client.execute( HttpHeaders.of(HttpMethod.POST, UnitTestServiceGrpc.getStaticUnaryCallMethod().getFullMethodName()) .set(HttpHeaderNames.CONTENT_TYPE, "application/protobuf") .set(GrpcHeaderNames.GRPC_ACCEPT_ENCODING, "gzip,none"), REQUEST_MESSAGE.toByteArray()).aggregate().get(); final SimpleResponse message = SimpleResponse.parseFrom(response.content().array()); assertThat(message).isEqualTo(RESPONSE_MESSAGE); assertThat(response.headers().getInt(HttpHeaderNames.CONTENT_LENGTH)) .isEqualTo(response.content().length()); checkRequestLog((rpcReq, rpcRes, grpcStatus) -> { assertThat(rpcReq.method()).isEqualTo("armeria.grpc.testing.UnitTestService/StaticUnaryCall"); assertThat(rpcReq.params()).containsExactly(REQUEST_MESSAGE); assertThat(rpcRes.get()).isEqualTo(RESPONSE_MESSAGE); }); }
@Test public void unframed_serviceError() throws Exception { final HttpClient client = HttpClient.of(server.httpUri("/")); final SimpleRequest request = SimpleRequest.newBuilder() .setResponseStatus( EchoStatus.newBuilder() .setCode(Status.DEADLINE_EXCEEDED.getCode().value())) .build(); final AggregatedHttpMessage response = client.execute( HttpHeaders.of(HttpMethod.POST, UnitTestServiceGrpc.getStaticUnaryCallMethod().getFullMethodName()) .set(HttpHeaderNames.CONTENT_TYPE, "application/protobuf"), request.toByteArray()).aggregate().get(); assertThat(response.status()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR); checkRequestLog((rpcReq, rpcRes, grpcStatus) -> { assertThat(rpcReq.method()).isEqualTo("armeria.grpc.testing.UnitTestService/StaticUnaryCall"); assertThat(rpcReq.params()).containsExactly(request); assertThat(grpcStatus).isNotNull(); assertThat(grpcStatus.getCode()).isEqualTo(Code.UNKNOWN); }); }
@Test(timeout = 10000) public void testMessageLogsForOneWay() throws Exception { final OnewayHelloService.Iface client = Clients.newClient(clientFactory(), getURI(Handlers.HELLO), Handlers.ONEWAYHELLO.iface(), clientOptions); recordMessageLogs = true; client.hello("trustin"); final RequestLog log = requestLogs.take(); assertThat(log.requestHeaders()).isInstanceOf(HttpHeaders.class); assertThat(log.requestContent()).isInstanceOf(RpcRequest.class); assertThat(log.rawRequestContent()).isInstanceOf(ThriftCall.class); final RpcRequest request = (RpcRequest) log.requestContent(); assertThat(request.serviceType()).isEqualTo(OnewayHelloService.Iface.class); assertThat(request.method()).isEqualTo("hello"); assertThat(request.params()).containsExactly("trustin"); final ThriftCall rawRequest = (ThriftCall) log.rawRequestContent(); assertThat(rawRequest.header().type).isEqualTo(TMessageType.ONEWAY); assertThat(rawRequest.header().name).isEqualTo("hello"); assertThat(rawRequest.args()).isInstanceOf(OnewayHelloService.hello_args.class); assertThat(((OnewayHelloService.hello_args) rawRequest.args()).getName()).isEqualTo("trustin"); assertThat(log.responseHeaders()).isInstanceOf(HttpHeaders.class); assertThat(log.responseContent()).isInstanceOf(RpcResponse.class); assertThat(log.rawResponseContent()).isNull(); final RpcResponse response = (RpcResponse) log.responseContent(); assertThat(response.get()).isNull(); }
@Test public void grpcWeb() throws Exception { final HttpClient client = HttpClient.of(server.httpUri("/")); final AggregatedHttpMessage response = client.execute( HttpHeaders.of(HttpMethod.POST, UnitTestServiceGrpc.getStaticUnaryCallMethod().getFullMethodName()) .set(HttpHeaderNames.CONTENT_TYPE, "application/grpc-web"), GrpcTestUtil.uncompressedFrame(GrpcTestUtil.requestByteBuf())).aggregate().get(); final byte[] serializedStatusHeader = "grpc-status: 0\r\n".getBytes(StandardCharsets.US_ASCII); final byte[] serializedTrailers = Bytes.concat( new byte[] { ArmeriaServerCall.TRAILERS_FRAME_HEADER }, Ints.toByteArray(serializedStatusHeader.length), serializedStatusHeader); assertThat(response.content().array()).containsExactly( Bytes.concat( GrpcTestUtil.uncompressedFrame( GrpcTestUtil.protoByteBuf(RESPONSE_MESSAGE)), serializedTrailers)); checkRequestLog((rpcReq, rpcRes, grpcStatus) -> { assertThat(rpcReq.method()).isEqualTo("armeria.grpc.testing.UnitTestService/StaticUnaryCall"); assertThat(rpcReq.params()).containsExactly(REQUEST_MESSAGE); assertThat(rpcRes.get()).isEqualTo(RESPONSE_MESSAGE); }); }