Skip to content

Commit

Permalink
Merge pull request #1531 from jedla97/grpc-global-interceptor
Browse files Browse the repository at this point in the history
Add test coverage for grpc GlobalInterceptor method annotation
  • Loading branch information
michalvavrik authored Nov 21, 2023
2 parents cd75746 + 64a9b5d commit 65089ef
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package io.quarkus.ts.http.advanced;

import static io.grpc.Metadata.ASCII_STRING_MARSHALLER;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;

import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.ClientCall;
import io.grpc.ClientInterceptor;
import io.grpc.ForwardingClientCall;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import io.quarkus.grpc.GlobalInterceptor;

class GrpcClientInterceptors {
public static Metadata.Key<String> CLIENT_METHOD = Metadata.Key.of("client-method-target", ASCII_STRING_MARSHALLER);
public static Metadata.Key<String> CLIENT_CLASS = Metadata.Key.of("client-class-target", ASCII_STRING_MARSHALLER);

@GlobalInterceptor
@ApplicationScoped
static class ClassTarget extends Base {
}

static class MethodTarget extends Base {
}

static class Producer {
@GlobalInterceptor
@Produces
MethodTarget methodTarget() {
return new MethodTarget();
}
}

abstract static class Base implements ClientInterceptor {
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions options,
Channel next) {
String interceptedTarget = getClass().getName();
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, options)) {
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
if (interceptedTarget.contains("MethodTarget")) {
headers.put(CLIENT_METHOD, interceptedTarget);
} else if (interceptedTarget.contains("ClassTarget")) {
headers.put(CLIENT_CLASS, interceptedTarget);
}
super.start(responseListener, headers);
}
};
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.quarkus.ts.http.advanced;

import io.grpc.stub.StreamObserver;
import io.quarkus.example.HelloReply;
import io.quarkus.example.InterceptedMessageGrpc;
import io.quarkus.example.InterceptedRequest;
import io.quarkus.grpc.GrpcService;

@GrpcService
public class GrpcInterceptorsService extends InterceptedMessageGrpc.InterceptedMessageImplBase {

@Override
public void showInterceptedMessage(InterceptedRequest request, StreamObserver<HelloReply> responseObserver) {
String serverMethod = GrpcServerInterceptors.SERVER_METHOD.get();
String serverClass = GrpcServerInterceptors.SERVER_CLASS.get();
HelloReply reply = HelloReply.newBuilder()
.setMessage("Intercepted client side method passed by server method interceptor is: " + serverMethod
+ "\nIntercepted client side class passed by server class interceptor is: " + serverClass)
.build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;

import io.quarkus.example.GreeterGrpc;
import io.quarkus.example.HelloReply;
import io.quarkus.example.HelloRequest;
import io.quarkus.example.InterceptedMessageGrpc;
import io.quarkus.example.InterceptedRequest;
import io.quarkus.grpc.GrpcClient;

@Path("/grpc")
Expand All @@ -18,11 +22,22 @@ public class GrpcResource {
@GrpcClient("hello")
GreeterGrpc.GreeterBlockingStub client;

@Inject
@GrpcClient("hello")
InterceptedMessageGrpc.InterceptedMessageBlockingStub interceptorsClient;

@GET
@Path("/{name}")
@Produces(MediaType.TEXT_PLAIN)
public String hello(@PathParam("name") String name) {
return client.sayHello(HelloRequest.newBuilder().setName(name).build()).getMessage();
}

@GET
@Path("global/interceptors")
public Response globalInterceptors() {
HelloReply helloReply = interceptorsClient.showInterceptedMessage(InterceptedRequest.newBuilder().build());
return Response.ok(helloReply.getMessage()).build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package io.quarkus.ts.http.advanced;

import static io.quarkus.ts.http.advanced.GrpcClientInterceptors.CLIENT_CLASS;
import static io.quarkus.ts.http.advanced.GrpcClientInterceptors.CLIENT_METHOD;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;

import io.grpc.Context;
import io.grpc.Contexts;
import io.grpc.Metadata;
import io.grpc.ServerCall;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import io.quarkus.grpc.GlobalInterceptor;

class GrpcServerInterceptors {

public static Context.Key<String> SERVER_METHOD = Context.key("server-method-target");
public static Context.Key<String> SERVER_CLASS = Context.key("server-class-target");

@GlobalInterceptor
@ApplicationScoped
static class ClassTarget extends Base {
}

static class MethodTarget extends Base {
}

static class Producer {
@GlobalInterceptor
@Produces
MethodTarget methodTarget() {
return new MethodTarget();
}
}

abstract static class Base implements ServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata metadata,
ServerCallHandler<ReqT, RespT> next) {
Context ctx = null;
String interceptedTarget = getClass().getName();
// Determine where was grpc call intercepted and put client side intercepted data to Context.
if (interceptedTarget.contains("MethodTarget")) {
ctx = Context.current().withValue(SERVER_METHOD, metadata.get(CLIENT_METHOD));
ctx.attach();
} else if (interceptedTarget.contains("ClassTarget")) {
ctx = Context.current().withValue(SERVER_CLASS, metadata.get(CLIENT_CLASS));
ctx.attach();
} else {
throw new RuntimeException("Unexpected intercepted class or method by GlobalInterceptor.");
}
return Contexts.interceptCall(ctx, call, metadata, next);
}
}
}
10 changes: 9 additions & 1 deletion http/http-advanced/src/main/proto/helloworld.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// Intercepted message service
service InterceptedMessage {
rpc ShowInterceptedMessage (InterceptedRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
string name = 1;
Expand All @@ -27,4 +32,7 @@ message HelloRequest {
// The response message containing the greetings
message HelloReply {
string message = 1;
}
}

message InterceptedRequest {
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,15 @@ public void testGrpc() {
getApp().given().when().get("/api/grpc/trinity").then().statusCode(HttpStatus.SC_OK).body(is("Hello trinity"));
}

@Test
@Tag("QUARKUS-3742")
@DisplayName("GRPC client and server global interceptors test")
public void testGrpcGlobalInterceptors() {
getApp().given().when().get("/api/grpc/global/interceptors").then().statusCode(HttpStatus.SC_OK)
.body(containsString("ClientInterceptors$ClassTarget"),
containsString("ClientInterceptors$MethodTarget"));
}

@Test
@DisplayName("Http/2 Server test")
public void http2Server() throws InterruptedException, URISyntaxException {
Expand Down

0 comments on commit 65089ef

Please sign in to comment.