Skip to content

Commit

Permalink
Added server reflection (#99)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomakehurst authored Aug 22, 2024
1 parent 253b9d7 commit 0250f65
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 27 deletions.
7 changes: 4 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ allprojects {
ext {
versions = [
wiremock: "3.2.0",
grpc : "1.65.1",
protobuf: "4.27.3"
grpc : "1.66.0",
protobuf: "3.25.3"
]

repoUser = this.hasProperty('sonatypeUser') ? sonatypeUser : 'default'
Expand Down Expand Up @@ -96,6 +96,7 @@ dependencies {

api platform("io.grpc:grpc-bom:$versions.grpc")
api "io.grpc:grpc-protobuf"
api "io.grpc:grpc-services"
api "io.grpc:grpc-stub"

implementation "io.grpc:grpc-servlet-jakarta"
Expand Down Expand Up @@ -211,7 +212,7 @@ configurations {

protobuf {
protoc {
artifact = "com.google.protobuf:protoc:4.27.3"
artifact = "com.google.protobuf:protoc:$versions.protobuf"
}

plugins {
Expand Down
85 changes: 63 additions & 22 deletions src/main/java/org/wiremock/grpc/internal/GrpcFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,19 @@
*/
package org.wiremock.grpc.internal;

import static com.github.tomakehurst.wiremock.common.Pair.pair;
import static java.util.concurrent.TimeUnit.SECONDS;

import com.github.tomakehurst.wiremock.common.Exceptions;
import com.github.tomakehurst.wiremock.common.Pair;
import com.github.tomakehurst.wiremock.http.StubRequestHandler;
import com.google.protobuf.Descriptors;
import com.google.protobuf.DynamicMessage;
import com.google.protobuf.TypeRegistry;
import io.grpc.BindableService;
import io.grpc.MethodDescriptor;
import io.grpc.ServerCallHandler;
import io.grpc.ServerServiceDefinition;
import io.grpc.*;
import io.grpc.protobuf.ProtoServiceDescriptorSupplier;
import io.grpc.protobuf.ProtoUtils;
import io.grpc.protobuf.services.ProtoReflectionServiceV1;
import io.grpc.servlet.jakarta.GrpcServlet;
import io.grpc.servlet.jakarta.ServletAdapter;
import io.grpc.stub.ServerCalls;
Expand All @@ -39,6 +40,7 @@
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class GrpcFilter extends HttpFilter {

Expand All @@ -60,27 +62,66 @@ private List<BindableService> buildServices(List<Descriptors.FileDescriptor> fil
final TypeRegistry typeRegistry = typeRegistryBuilder.build();
JsonMessageConverter jsonMessageConverter = new JsonMessageConverter(typeRegistry);

return fileDescriptors.stream()
.flatMap(fileDescriptor -> fileDescriptor.getServices().stream())
.map(
serviceDescriptor ->
(BindableService)
final Stream<BindableService> servicesFromDescriptors =
fileDescriptors.stream()
.flatMap(
fileDescriptor ->
fileDescriptor.getServices().stream()
.map(service -> pair(fileDescriptor, service)))
.map(
fileAndServiceDescriptor ->
() -> {
final Descriptors.FileDescriptor fileDescriptor = fileAndServiceDescriptor.a;
final Descriptors.ServiceDescriptor serviceDescriptor =
fileAndServiceDescriptor.b;
final ServiceDescriptor.Builder serviceDescriptorBuilder =
ServiceDescriptor.newBuilder(serviceDescriptor.getFullName())
.setSchemaDescriptor(
new ProtoServiceDescriptorSupplier() {

@Override
public Descriptors.FileDescriptor getFileDescriptor() {
return fileDescriptor;
}

@Override
public Descriptors.ServiceDescriptor getServiceDescriptor() {
return serviceDescriptor;
}
});

final List<
Pair<
MethodDescriptor<DynamicMessage, DynamicMessage>,
ServerCallHandler<DynamicMessage, DynamicMessage>>>
methodDescriptorHandlerPairs =
serviceDescriptor.getMethods().stream()
.map(
methodDescriptor ->
pair(
buildMessageDescriptorInstance(
serviceDescriptor, methodDescriptor),
buildHandler(
serviceDescriptor,
methodDescriptor,
jsonMessageConverter)))
.collect(Collectors.toList());

methodDescriptorHandlerPairs.stream()
.map(pair -> pair.a)
.forEach(serviceDescriptorBuilder::addMethod);

final ServerServiceDefinition.Builder builder =
ServerServiceDefinition.builder(serviceDescriptor.getFullName());
serviceDescriptor
.getMethods()
.forEach(
methodDescriptor ->
builder.addMethod(
buildMessageDescriptorInstance(
serviceDescriptor, methodDescriptor),
buildHandler(
serviceDescriptor,
methodDescriptor,
jsonMessageConverter)));
ServerServiceDefinition.builder(serviceDescriptorBuilder.build());

methodDescriptorHandlerPairs.forEach(
pair -> builder.addMethod(pair.a, pair.b));

return builder.build();
})
});

final BindableService reflectionService = ProtoReflectionServiceV1.newInstance();
return Stream.concat(servicesFromDescriptors, Stream.of(reflectionService))
.collect(Collectors.toUnmodifiableList());
}

Expand Down
46 changes: 44 additions & 2 deletions src/test/java/org/wiremock/grpc/GrpcAcceptanceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.*;
import static org.wiremock.grpc.dsl.WireMockGrpc.*;

import com.example.grpc.AnotherGreetingServiceGrpc;
Expand All @@ -35,7 +35,15 @@
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;
import io.grpc.reflection.v1.ServerReflectionGrpc;
import io.grpc.reflection.v1.ServerReflectionRequest;
import io.grpc.reflection.v1.ServerReflectionResponse;
import io.grpc.reflection.v1.ServiceResponse;
import io.grpc.stub.StreamObserver;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -427,4 +435,38 @@ void unaryMethodWithAnyResponseFromJson() {

assertThat(typeUrl, is("type.googleapis.com/com.example.grpc.response.HelloResponse"));
}

@Test
void reflection() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
List<ServerReflectionResponse> serverReflectionResponses = new ArrayList<>();
StreamObserver<ServerReflectionRequest> stream =
ServerReflectionGrpc.newStub(channel)
.serverReflectionInfo(
new StreamObserver<>() {
@Override
public void onNext(ServerReflectionResponse value) {
serverReflectionResponses.add(value);
}

@Override
public void onError(Throwable t) {
t.printStackTrace(System.err);
}

@Override
public void onCompleted() {
latch.countDown();
}
});
stream.onNext(ServerReflectionRequest.newBuilder().setListServices("").build());
stream.onCompleted();
assertTrue(latch.await(5, SECONDS));

System.out.println(serverReflectionResponses);

List<ServiceResponse> serviceList =
serverReflectionResponses.get(0).getListServicesResponse().getServiceList();
assertThat(serviceList.size(), is(4));
}
}

0 comments on commit 0250f65

Please sign in to comment.