From 8a41ffecd83ad14e9a75ce25efb99f69de787110 Mon Sep 17 00:00:00 2001 From: Matthew Pearson Date: Fri, 31 May 2024 17:45:06 +0100 Subject: [PATCH] Log requests, as mentioned in issue 38. --- .../ClientStreamingServerCallHandler.java | 9 +- .../wiremock/grpc/internal/GrpcFilter.java | 9 +- .../grpc/internal/GrpcHttpServerFactory.java | 2 +- .../grpc/internal/UnaryServerCallHandler.java | 9 +- .../org/wiremock/grpc/GrpcAcceptanceTest.java | 90 ++++++++++++++++++- .../java/org/wiremock/grpc/TestNotifier.java | 41 +++++++++ 6 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 src/test/java/org/wiremock/grpc/TestNotifier.java diff --git a/src/main/java/org/wiremock/grpc/internal/ClientStreamingServerCallHandler.java b/src/main/java/org/wiremock/grpc/internal/ClientStreamingServerCallHandler.java index ea493b5..dd28bac 100644 --- a/src/main/java/org/wiremock/grpc/internal/ClientStreamingServerCallHandler.java +++ b/src/main/java/org/wiremock/grpc/internal/ClientStreamingServerCallHandler.java @@ -18,6 +18,8 @@ import static org.wiremock.grpc.dsl.GrpcResponseDefinitionBuilder.GRPC_STATUS_NAME; import static org.wiremock.grpc.dsl.GrpcResponseDefinitionBuilder.GRPC_STATUS_REASON; +import com.github.tomakehurst.wiremock.common.LocalNotifier; +import com.github.tomakehurst.wiremock.common.Notifier; import com.github.tomakehurst.wiremock.http.HttpHeader; import com.github.tomakehurst.wiremock.http.StubRequestHandler; import com.github.tomakehurst.wiremock.stubbing.ServeEvent; @@ -32,12 +34,16 @@ public class ClientStreamingServerCallHandler extends BaseCallHandler implements ServerCalls.ClientStreamingMethod { + private final Notifier notifier; + public ClientStreamingServerCallHandler( StubRequestHandler stubRequestHandler, Descriptors.ServiceDescriptor serviceDescriptor, Descriptors.MethodDescriptor methodDescriptor, - JsonMessageConverter jsonMessageConverter) { + JsonMessageConverter jsonMessageConverter, + Notifier notifier) { super(stubRequestHandler, serviceDescriptor, methodDescriptor, jsonMessageConverter); + this.notifier = notifier; } @Override @@ -64,6 +70,7 @@ public void onNext(DynamicMessage request) { methodDescriptor.getName(), jsonMessageConverter.toJson(request)); + LocalNotifier.set(notifier); stubRequestHandler.handle( wireMockRequest, (req, resp, attributes) -> { diff --git a/src/main/java/org/wiremock/grpc/internal/GrpcFilter.java b/src/main/java/org/wiremock/grpc/internal/GrpcFilter.java index da992f3..49eb0c1 100644 --- a/src/main/java/org/wiremock/grpc/internal/GrpcFilter.java +++ b/src/main/java/org/wiremock/grpc/internal/GrpcFilter.java @@ -18,6 +18,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; import com.github.tomakehurst.wiremock.common.Exceptions; +import com.github.tomakehurst.wiremock.common.Notifier; import com.github.tomakehurst.wiremock.http.StubRequestHandler; import com.google.protobuf.Descriptors; import com.google.protobuf.DynamicMessage; @@ -42,13 +43,15 @@ public class GrpcFilter extends HttpFilter { private final GrpcServlet grpcServlet; private final StubRequestHandler stubRequestHandler; private final List fileDescriptors; + private final Notifier notifier; private final JsonMessageConverter jsonMessageConverter; public GrpcFilter( - StubRequestHandler stubRequestHandler, List fileDescriptors) { + StubRequestHandler stubRequestHandler, List fileDescriptors, Notifier notifier) { this.stubRequestHandler = stubRequestHandler; this.fileDescriptors = fileDescriptors; + this.notifier = notifier; final TypeRegistry.Builder typeRegistryBuilder = TypeRegistry.newBuilder(); fileDescriptors.forEach( @@ -90,10 +93,10 @@ private ServerCallHandler buildHandler( return methodDescriptor.isClientStreaming() ? ServerCalls.asyncClientStreamingCall( new ClientStreamingServerCallHandler( - stubRequestHandler, serviceDescriptor, methodDescriptor, jsonMessageConverter)) + stubRequestHandler, serviceDescriptor, methodDescriptor, jsonMessageConverter, notifier)) : ServerCalls.asyncUnaryCall( new UnaryServerCallHandler( - stubRequestHandler, serviceDescriptor, methodDescriptor, jsonMessageConverter)); + stubRequestHandler, serviceDescriptor, methodDescriptor, jsonMessageConverter, notifier)); } private static MethodDescriptor buildMessageDescriptorInstance( diff --git a/src/main/java/org/wiremock/grpc/internal/GrpcHttpServerFactory.java b/src/main/java/org/wiremock/grpc/internal/GrpcHttpServerFactory.java index 79382e8..c85d997 100644 --- a/src/main/java/org/wiremock/grpc/internal/GrpcHttpServerFactory.java +++ b/src/main/java/org/wiremock/grpc/internal/GrpcHttpServerFactory.java @@ -79,7 +79,7 @@ public HttpServer buildHttpServer( protected void decorateMockServiceContextBeforeConfig( ServletContextHandler mockServiceContext) { - final GrpcFilter grpcFilter = new GrpcFilter(stubRequestHandler, fileDescriptors); + final GrpcFilter grpcFilter = new GrpcFilter(stubRequestHandler, fileDescriptors, options.notifier()); final FilterHolder filterHolder = new FilterHolder(grpcFilter); mockServiceContext.addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST)); } diff --git a/src/main/java/org/wiremock/grpc/internal/UnaryServerCallHandler.java b/src/main/java/org/wiremock/grpc/internal/UnaryServerCallHandler.java index 0cb1e88..a3f8b4f 100644 --- a/src/main/java/org/wiremock/grpc/internal/UnaryServerCallHandler.java +++ b/src/main/java/org/wiremock/grpc/internal/UnaryServerCallHandler.java @@ -19,6 +19,8 @@ import static org.wiremock.grpc.dsl.GrpcResponseDefinitionBuilder.GRPC_STATUS_REASON; import static org.wiremock.grpc.internal.Delays.delayIfRequired; +import com.github.tomakehurst.wiremock.common.LocalNotifier; +import com.github.tomakehurst.wiremock.common.Notifier; import com.github.tomakehurst.wiremock.http.HttpHeader; import com.github.tomakehurst.wiremock.http.StubRequestHandler; import com.github.tomakehurst.wiremock.stubbing.ServeEvent; @@ -32,12 +34,16 @@ public class UnaryServerCallHandler extends BaseCallHandler implements ServerCalls.UnaryMethod { + private final Notifier notifier; + public UnaryServerCallHandler( StubRequestHandler stubRequestHandler, Descriptors.ServiceDescriptor serviceDescriptor, Descriptors.MethodDescriptor methodDescriptor, - JsonMessageConverter jsonMessageConverter) { + JsonMessageConverter jsonMessageConverter, + Notifier notifier) { super(stubRequestHandler, serviceDescriptor, methodDescriptor, jsonMessageConverter); + this.notifier = notifier; } @Override @@ -53,6 +59,7 @@ public void invoke(DynamicMessage request, StreamObserver respon methodDescriptor.getName(), jsonMessageConverter.toJson(request)); + LocalNotifier.set(notifier); stubRequestHandler.handle( wireMockRequest, (req, resp, attributes) -> { diff --git a/src/test/java/org/wiremock/grpc/GrpcAcceptanceTest.java b/src/test/java/org/wiremock/grpc/GrpcAcceptanceTest.java index 096d4e6..15e6faf 100644 --- a/src/test/java/org/wiremock/grpc/GrpcAcceptanceTest.java +++ b/src/test/java/org/wiremock/grpc/GrpcAcceptanceTest.java @@ -17,6 +17,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.*; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static org.hamcrest.collection.IsEmptyCollection.empty; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -54,6 +55,7 @@ public class GrpcAcceptanceTest { GreetingsClient greetingsClient; AnotherGreetingsClient anotherGreetingsClient; WireMock wireMock; + TestNotifier notifier; @RegisterExtension public static WireMockExtension wm = @@ -62,7 +64,8 @@ public class GrpcAcceptanceTest { wireMockConfig() .dynamicPort() .withRootDirectory("src/test/resources/wiremock") - .extensions(new GrpcExtensionFactory())) + .extensions(new GrpcExtensionFactory()) + .notifier(new TestNotifier())) .build(); @BeforeEach @@ -78,6 +81,9 @@ void init() { anotherChannel = ManagedChannelBuilder.forAddress("localhost", wm.getPort()).usePlaintext().build(); anotherGreetingsClient = new AnotherGreetingsClient(anotherChannel); + + notifier = (TestNotifier) wm.getOptions().notifier(); + notifier.clear(); } @AfterEach @@ -100,6 +106,9 @@ void shouldReturnGreetingBuiltViaTemplatedJsonWithRawStubbing() { String greeting = greetingsClient.greet("Tom"); assertThat(greeting, is("Hello Tom")); + + assertNoErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -112,6 +121,9 @@ void shouldReturnGreetingBuiltViaTemplatedJson() { String greeting = greetingsClient.greet("Tom"); assertThat(greeting, is("Hello Tom")); + + assertNoErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -122,6 +134,9 @@ void returnsResponseBuiltFromJson() { String greeting = greetingsClient.greet("Whatever"); assertThat(greeting, is("Hi Tom from JSON")); + + assertNoErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -133,6 +148,9 @@ void returnsResponseBuiltFromMessageObject() { String greeting = greetingsClient.greet("Whatever"); assertThat(greeting, is("Hi Tom from object")); + + assertNoErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -145,6 +163,9 @@ void matchesRequestViaCoreJsonMatcher() { assertThat(greetingsClient.greet("Tom"), is("OK")); assertThrows(StatusRuntimeException.class, () -> greetingsClient.greet("Wrong")); + + assertSomeErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -160,6 +181,9 @@ void matchesRequestViaExactMessageEquality() { assertThrows(StatusRuntimeException.class, () -> greetingsClient.greet("Wrong")); assertThat( exception.getMessage(), is("NOT_FOUND: No matching stub mapping found for gRPC request")); + + assertSomeErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -170,6 +194,9 @@ void returnsResponseWithStatus() { StatusRuntimeException exception = assertThrows(StatusRuntimeException.class, () -> greetingsClient.greet("Whatever")); assertThat(exception.getMessage(), is("FAILED_PRECONDITION: Failed some blah prerequisite")); + + assertNoErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -180,6 +207,9 @@ void returnsUnaryResponseToFirstMatchingMessagesInStreamingRequest() { .willReturn(message(HelloResponse.newBuilder().setGreeting("Hi Rob")))); assertThat(greetingsClient.manyGreetingsOneReply("Tom", "Uri", "Rob", "Mark"), is("Hi Rob")); + + assertSomeErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -197,6 +227,9 @@ void throwsNotFoundWhenNoStreamingClientMessageMatches() { assertThat( exception.getCause().getMessage(), is("NOT_FOUND: No matching stub mapping found for gRPC request")); + + assertSomeErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -211,6 +244,9 @@ void throwsReturnedErrorFromStreamingClientCall() { Exception.class, () -> greetingsClient.manyGreetingsOneReply("Tom", "Jerf", "Rob")); assertThat(exception.getCause(), instanceOf(StatusRuntimeException.class)); assertThat(exception.getCause().getMessage(), is("INVALID_ARGUMENT: Jerf is not a valid name")); + + assertSomeErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -220,6 +256,9 @@ void returnsStreamedResponseToUnaryRequest() { .willReturn(message(HelloResponse.newBuilder().setGreeting("Hi Tom")))); assertThat(greetingsClient.oneGreetingManyReplies("Tom"), hasItem("Hi Tom")); + + assertNoErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -228,6 +267,9 @@ void returnsResponseWithImportedType() { method("oneGreetingEmptyReply").willReturn(message(Empty.newBuilder()))); assertThat(greetingsClient.oneGreetingEmptyReply("Tom"), is(true)); + + assertNoErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -247,6 +289,9 @@ void verifiesViaJson() { mockGreetingService .verify(0, "greeting") .withRequestMessage(equalToJson("{ \"name\": \"Chris\" }")); + + assertNoErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -261,6 +306,9 @@ void verifiesViaMessage() { .withRequestMessage(equalToMessage(HelloRequest.newBuilder().setName("Peter"))); mockGreetingService.verify(0, "oneGreetingEmptyReply"); + + assertNoErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -270,6 +318,9 @@ void networkFault() { Exception exception = assertThrows(StatusRuntimeException.class, () -> greetingsClient.greet("Alan")); assertThat(exception.getMessage(), startsWith("UNKNOWN")); + + assertNoErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -285,6 +336,9 @@ void fixedDelay() { assertThat(greeting, is("Delayed hello")); assertThat(stopwatch.elapsed(), greaterThanOrEqualTo(Duration.ofMillis(1000L))); + + assertNoErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -300,6 +354,9 @@ void randomDelay() { assertThat(greeting, is("Delayed hello")); assertThat(stopwatch.elapsed(), greaterThanOrEqualTo(Duration.ofMillis(500L))); + + assertNoErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -326,6 +383,9 @@ void resetStubs() { anotherMockGreetingService.removeAllStubs(); verifyDefaultMappings(); + + assertNoErrorMessages(); + assertNoInfoMessages(); } private void verifyDefaultMappings() { @@ -391,6 +451,9 @@ void resetAll() { anotherMockGreetingService .verify(6, "anotherGreeting") .withRequestMessage(equalToMessage(HelloRequest.newBuilder().setName("Tom"))); + + assertNoErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -402,6 +465,9 @@ void unaryMethodWithAnyRequest() { String greeting = greetingsClient.greetAnyRequest(); assertThat(greeting, is("Hiya")); + + assertNoErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -413,6 +479,9 @@ void unaryMethodWithAnyResponse() { String typeUrl = greetingsClient.greetAnyResponse(); assertThat(typeUrl, is("type.googleapis.com/com.example.grpc.response.HelloResponse")); + + assertNoErrorMessages(); + assertSomeInfoMessages(); } @Test @@ -426,5 +495,24 @@ void unaryMethodWithAnyResponseFromJson() { String typeUrl = greetingsClient.greetAnyResponse(); assertThat(typeUrl, is("type.googleapis.com/com.example.grpc.response.HelloResponse")); + + assertNoErrorMessages(); + assertSomeInfoMessages(); + } + + private void assertNoInfoMessages() { + assertThat("Should not be any info messages", notifier.infoMessages, is(empty())); + } + + private void assertSomeInfoMessages() { + assertThat("Should be some info messages", notifier.infoMessages, is(not(empty()))); + } + + private void assertNoErrorMessages() { + assertThat("Should not be any error messages", notifier.errorMessages, is(empty())); + } + + private void assertSomeErrorMessages() { + assertThat("Should be some error messages", notifier.errorMessages, is(not(empty()))); } } diff --git a/src/test/java/org/wiremock/grpc/TestNotifier.java b/src/test/java/org/wiremock/grpc/TestNotifier.java new file mode 100644 index 0000000..c532a61 --- /dev/null +++ b/src/test/java/org/wiremock/grpc/TestNotifier.java @@ -0,0 +1,41 @@ +package org.wiremock.grpc; + +import com.github.tomakehurst.wiremock.common.Notifier; + +import java.util.ArrayList; +import java.util.List; + +public class TestNotifier implements Notifier { + + public List infoMessages = new ArrayList<>(); + public List errorMessages = new ArrayList<>(); + public List throwables = new ArrayList<>(); + + public int numberOfMessages = 0; + + public void clear() { + infoMessages.clear(); + errorMessages.clear(); + throwables.clear(); + numberOfMessages = 0; + } + + @Override + public void info(String message) { + infoMessages.add(message); + System.out.println(++numberOfMessages + "\t" + message); + } + + @Override + public void error(String message) { + errorMessages.add(message); + System.err.println(++numberOfMessages + "\t" + message); + } + + @Override + public void error(String message, Throwable t) { + errorMessages.add(message); + throwables.add(t); + System.err.println(++numberOfMessages + "\t" + message); + } +}