fadelis / grpcmock Goto Github PK
View Code? Open in Web Editor NEWA gRPC Java testing tool to easily mock endpoints of gRPC services for IT or Unit testing
Home Page: http://grpcmock.org
License: Apache License 2.0
A gRPC Java testing tool to easily mock endpoints of gRPC services for IT or Unit testing
Home Page: http://grpcmock.org
License: Apache License 2.0
I am trying to use GrpcMock for performance tests with Gatling.
I created a grpcMock server that returns the appropriate mock response for various requests based on request matching (unary grpc method in all cases). In other words, I specified the sample requests and sample responses for the GrpcMock
server.
Gatling is used to check the responses received from the GrpcMock
and make sure that the responses include the appropriate fields, they are completed in time, etc. and the requests are predefined thus I need no checks on the GrpcMock
server.
The test works fine as long as I run it locally, though when I run it on the build server, the test fails due to slow response times. Note that there is a high amount of requests: the GrpcMock
server receives 160 requests in 10 seconds.
I think the test could be completed faster if I had an option to disable the logging of the received requests on the GrpcMock
server.
I could not find any workaround to bypass the RequestCaptureInterceptor.
This interceptor is always passed to the server when it is built.
Could you add a configuration option to disable this interceptor? Or maybe make it optional to pass interceptors to the mock server?
I'm attempting to write a test case utilizing an AbstractFutureStub
and am running into an issue chaining multiple responses. Basically all calls to the future stub return the initial response and never the 'next' response:
stubFor(unaryMethod(TestingServiceGrpc.getCreateMethod())
.willReturn(response(WorkflowTracker.newBuilder()
.setId("id1")
.setClientId("clientId1")
.build()).withFixedDelay(Duration.ofMillis(200)))
.nextWillReturn(response(WorkflowTracker.newBuilder()
.setId("id2")
.setClientId("clientId2")
.build())));
ListenableFuture<WorkflowTracker> fut1 = stub.create(CreateRequest.newBuilder().build());
ListenableFuture<WorkflowTracker> fut2 = stub.create(CreateRequest.newBuilder().build());
try {
WorkflowTracker tracker1 = fut1.get();
WorkflowTracker tracker2 = fut2.get();
assertNotEquals(tracker1, tracker2);
} catch (Exception e) {
fail();
}
But the exact same test using an AbstractBlockingStub
works as expected, where the first call to create
returns the first response, and the second call to create
returns the second response. Is it expected that we should be able to mock sequential responses with a AbstractFutureStub
?
In my app I will be firing off many requests in parallel and I'd like to get unique responses for each request, but not sure how to simulate this. Note that if I move the fut1.get()
above the second stub.create()
it works as expected... but this is not how my app will be calling the stub so it would not be an accurate test. The below test works as expected since I presume it's more similar to a blocking stub.
ListenableFuture<WorkflowTracker> fut1 = stub.create(CreateRequest.newBuilder().build());
WorkflowTracker tracker1 = fut1.get();
ListenableFuture<WorkflowTracker> fut2 = stub.create(CreateRequest.newBuilder().build());
WorkflowTracker tracker2 = fut2.get();
Every time I make a request to a mock server I've started with grpcmock, I get an output like this:
Received request:
Request to some.path.HelloWorldAPI/Hello method
with headers:
Metadata(content-type=application/grpc,user-agent=grpc-java-netty/1.44.0,foo=bar)
with request:
some_request_object {
foo: "bar"
}
When making a lot of requests during testing this gets a little annoying and can pollute the logs. Could we be given the option to turn this off? If this ability already exists, could it be documented more clearly?
Hi,
First of all, thank you very much for this library. We are using it for our unit test and it really helps us.
Since you defined "configureFor" as a static function, and since you implemented your library to create global static gRPC Mock instance, it is impossible to use this library in order to run multiple instances of gRPC mock server in parallel on the same time on different ports.
It is important for us since we are running our unit tests in parallel and we have multiple gRPC servers that we want to mock while we are testing our clients against them.
We wanted to ask you if is it possible to change it so we can run it in parallel as I described, and if so, if you will be able to change it.
Thanks again.
We have lots of tests that start gRPC mock servers. Even though they all set the port to 0 so a random port is selected, there's still a chance that two tests try to use the same random port. See the screenshot below.
Is there a way to configure the mock server so it retries a few times when seeing such an error? Thanks!
Currently, the interface StreamRequestProxyResponseBuilderStep is implemented by classes supporting streaming from the client-side (client and bidi streams). However, it would be extremely beneficial to add this functionality for other communication types (server stream and unary).
We use this library not for testing purposes, but as an embedded mock server for our local development experience. Method 'willProxyTo' allows providing a custom dynamic behavior. Therefore, besides predefined responses, we could provide implementations handling request values in runtime.
I'm trying to incorporate this library into an application that is using Quarkus and gRPC. I think there is an overall design flaw which prevents this library from being able to be used...
In the GrpcMock
class it uses a ThreadLocal
for the instance to use:
private static final ThreadLocal<GrpcMock> INSTANCE = ThreadLocal
.withInitial(() -> grpcMock().build());
When running in Quarkus or on top of Vertx, the thread that the stub was created on and the thread which actually executes the request are 2 different threads, therefore the stubs are never able to be looked up because of the fact that all the storage is based on a ThreadLocal
.
is there an possibility to delay a stream reply not by a fixed or random amount of time, but instead send the next stream reply when a message is received in a different handler?
for example i have an unary endpoint and a streaming endpoint, and the streaming endpoint sends the replies to requests to the unary endpoint, so anytime the unary endpoint receives a message I want to trigger the next reply in the streaming endpoint.
so instead of this:
grpcMock.register(....)
.withRequest(...).willReturn(stream(
response(...)
.withFixedDelay(1))
.and(...).withFixedDelay(100))
the stream reply could be delayed until a future is resolved
future=CompletableFuture()
grpcMock.register(....)
.withRequest(...).willReturn(stream(
response(...)
.withFixedDelay(1))
.and(...).delayUntil(future))
and in my unary mock i then resolve the future when I get a request (also not sure how to best do that)
anyway its just an idea, is that something that would be easy to add to grpcmock, or is there even already a way to achieve what I want?
Does the library support Kotest and Grpc services implemented in Kotlin?
I keep getting UNIMPLEMENTED
even though I can see in the logs that the requests hit GrpcMock.
I suspect that the stubFor
doesn't really work properly with those 2 Kotlin libraries.
import io.grpc.ManagedChannel
import io.grpc.inprocess.InProcessChannelBuilder
import io.kotest.core.spec.Spec
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.result.shouldBeSuccess
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import org.assertj.core.api.Assertions.assertThat
import org.grpcmock.GrpcMock
import org.grpcmock.GrpcMock.calledMethod
import org.grpcmock.GrpcMock.stubFor
import org.grpcmock.GrpcMock.unaryMethod
import org.grpcmock.GrpcMock.verifyThat
import org.grpcmock.springboot.AutoConfigureGrpcMock
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.ActiveProfiles
@SpringBootTest
@MockDatabase
@AutoConfigureGrpcMock(useInProcessServer = true, name = "test")
@ActiveProfiles("test")
class XGrpcClientTestLib(
val client: XGrpcClient,
val grpcMock: GrpcMock,
) : FunSpec() {
@Value("\${grpcmock.server.name}")
private val inProcessName: String? = null
lateinit var channel: ManagedChannel
override suspend fun beforeSpec(spec: Spec) {
channel = InProcessChannelBuilder.forName(inProcessName)
.usePlaintext()
.build();
}
override suspend fun afterSpec(spec: Spec) {
channel.shutdownNow()
}
init {
test("getX should return correct response") {
val expectedRequest = GetXRequest.newBuilder()
.setXName("name")
.setXKey("x)
.build()
val expectedResponse = GetXResponse.newBuilder()
.setX("success")
.build()
stubFor(
unaryMethod(XGrpcServiceGrpcKt.getXForUserMethod)
.withRequest(expectedRequest)
.willReturn(expectedResponse)
)
val variant = client.getVariant(xName, xKey)
variant.shouldBeSuccess().shouldBe("xSuccess")
verifyThat(
calledMethod(XGrpcServiceGrpcKt.getXForUserMethod)
.withRequest(expectedRequest),
)
}
}
}
I would like to verify my grpc requests with my assertion lib instead of using verify, something like
List<CapturedRequest> l = grpcMock.getRequestsFor(calledMethod(...))
assertThat(l...)
mainly to get better error messages and because I think asserting should be left to assertion libs.
Spring Boot 3 has removed the org.springframework.util.SocketUtils
class, which this lib requires.
org/springframework/util/SocketUtils
java.lang.NoClassDefFoundError: org/springframework/util/SocketUtils
at org.grpcmock.springboot.GrpcMockApplicationListener.registerPort(GrpcMockApplicationListener.java:43)
at org.grpcmock.springboot.GrpcMockApplicationListener.onApplicationEvent(GrpcMockApplicationListener.java:23)
at org.grpcmock.springboot.GrpcMockApplicationListener.onApplicationEvent(GrpcMockApplicationListener.java:19)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131)
at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136)
at org.springframework.boot.context.event.EventPublishingRunListener.contextLoaded(EventPublishingRunListener.java:98)
at org.springframework.boot.SpringApplicationRunListeners.lambda$contextLoaded$4(SpringApplicationRunListeners.java:72)
at java.base/java.lang.Iterable.forEach(Iterable.java:75)
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118)
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:112)
at org.springframework.boot.SpringApplicationRunListeners.contextLoaded(SpringApplicationRunListeners.java:72)
at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:412)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:137)
at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:59)
at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:47)
at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1386)
at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:543)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:137)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:108)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:183)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:127)
at org.grpcmock.springboot.GrpcMockTestExecutionListener.applicationContextBroken(GrpcMockTestExecutionListener.java:82)
at org.grpcmock.springboot.GrpcMockTestExecutionListener.isInvalidContext(GrpcMockTestExecutionListener.java:55)
at org.grpcmock.springboot.GrpcMockTestExecutionListener.beforeTestClass(GrpcMockTestExecutionListener.java:21)
at org.springframework.test.context.TestContextManager.beforeTestClass(TestContextManager.java:214)
at org.springframework.test.context.junit.jupiter.SpringExtension.beforeAll(SpringExtension.java:113)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeBeforeAllCallbacks$12(ClassBasedTestDescriptor.java:395)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeBeforeAllCallbacks(ClassBasedTestDescriptor.java:395)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:211)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:84)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:148)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:55)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at jdk.proxy2/jdk.proxy2.$Proxy5.stop(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
Caused by: java.lang.ClassNotFoundException: org.springframework.util.SocketUtils
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
... 89 more
Is there already work in progress towards getting an updated version?
Thanks
Hi,
I have a problem with running integration tests in parallel which I solved and I just wanted to notify you about the problem. It seems like the grpcmock is shared between tests. (Atleast in the way I am using it)
I am unable to use the @AutoConfigureGrpcMock
since I am using the starter from https://github.com/yidongnan/grpc-spring-boot-starter and need to set the address via @DynamicPropertySource
like this:
@DynamicPropertySource
static void overwriteProperties(DynamicPropertyRegistry registry) {
registry.add("grpc.client.<client>.address") { "static://localhost:$GrpcMock.globalPort()" }
}
I start the server like this:
def setupSpec() {
grpcMock = GrpcMock.grpcMock().build().start()
GrpcMock.configureFor(grpcMock)
}
When I run tests in parallel I will get an error with the port being taken.
I found the following in your code and it turns out that the socket.setReuseAddress(true);
in findFreePort
is what is causing the issue, so by removing it is resolved.
private static int findFreePort() {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
} catch (IOException e) {
throw new GrpcMockException("Failed finding a free port", e);
}
}
Doesn't work with StatusRuntimeException!
Our Grpc Service throw StatusRuntimeException.
I tried your GrpcMock and i can't to throw exception from stubFor. I saw that i can return Status, but not Exception.
Please, help me) May be in your library it is impossible?
Do I understand correctly that with this library, i can raise a real gRPC service, on the host and port that I specified, which will be available from the outside?
For example, can the gRPC client launched by me separately (for example, in a separate JVM), call a method defined in this server, and then inside the test, I can call verify() to check that the method that the client accessed was called on the server and with what kind of arguments.
now I got one proto file , if i want mock grpc sevrice by this proto ,how can i integrate this project with my request , i check your example , it's hard for me to understand , btw ,i am new in grpc cycle . tks
I am using Armeria https://armeria.dev/docs/client-grpc and creating a Grpc Client like this
val client = Clients
.builder(url)
.decorator(LoggingClient.newDecorator())
.build(DownstreamServiceGrpc.DownstreamServiceBlockingStub::class.java)
And then making a call with,
client.someGrpcMethod()
I am running integration test with SpringBootTest and I am not able to stub the downstream call.
Also the url looks like, in application.yml, as:
url: gproto+https://localhost:${grpcmock.server.port:443}
I have tried adding the grpcmock.server.port this way, but it doesn't seem to take effect. Any way around this?
With a structure like this:
@ExtendWith(GrpcMockExtension.class)
class TestClass {
private ManagedChannel channel;
@BeforeEach
void setupChannel() {
channel = ManagedChannelBuilder.forAddress("localhost", GrpcMock.getGlobalPort())
.usePlaintext()
.build();
}
@AfterEach
void shutdownChannel() {
Optional.ofNullable(channel).ifPresent(ManagedChannel::shutdownNow);
}
@Nested
@DisplayName("when the request succeeds")
class RequestSucceedsTest {
@BeforeEach
void setUpSuccessfulGrpcRequest() {
stubFor(unaryMethod(SimpleServiceGrpc.getUnaryRpcMethod())
.willReturn(successResponse));
}
@Test
@DisplayName("it returns foo")
void returnsFoo() {
// request and assertions here
}
}
@Nested
@DisplayName("when the request fails")
class RequestFailsTest {
@BeforeEach
void setUpUnsuccessfulGrpcRequest() {
stubFor(unaryMethod(SimpleServiceGrpc.getUnaryRpcMethod())
.willReturn(failureResponse));
}
@Test
@DisplayName("it returns bar")
void returnsBar() {
// request and assertions here
}
}
}
The stubbing works properly, and the tests pass.
One of the two tests encounters a StatusRuntimeException
, with a message of Already terminated
.
I want to use grpcmock for unit testing, but I've encountered an issue
Here is my code
public static void adaptException(Runnable runnable, StreamObserver streamObserver) {
try {
runnable.run();
} catch (ApiException e) {
Metadata trailers = new Metadata();
Map errorMap = JacksonUtil.readValue(JacksonUtil.writeValueAsString(e), Map.class);
errorMap.remove("stackTrace");
trailers.put(Metadata.Key.of("error", Metadata.ASCII_STRING_MARSHALLER),
JacksonUtil.writeValueAsString(errorMap));
int errorCode = e.getErrorCode();
String errorMessage = e.getErrorMessage();
if (errorCode == INTERNAL_UNAUTHORIZED) {
streamObserver.onError(
new StatusRuntimeException(Status.PERMISSION_DENIED.withDescription(errorMessage), trailers));
} else if (TOKEN_ERROR_CODES.contains(errorCode)) {
streamObserver.onError(
new StatusRuntimeException(Status.UNAUTHENTICATED.withDescription(errorMessage), trailers));
} else {
streamObserver.onError(new StatusRuntimeException(Status.UNKNOWN.withDescription(errorMessage), trailers));
}
} catch (Throwable e) {
log.error("adaptException error", e);
streamObserver.onError(new StatusRuntimeException(Status.UNKNOWN));
}
}
I put error information in the metadata. And consumer can get the error info.
I want to know how can I mock it?I didn't find a similar usage in the source code of grpcmock.
I tried the following code,but it didn't work
Metadata trailers = new Metadata();
trailers.put(Metadata.Key.of("error", Metadata.ASCII_STRING_MARSHALLER), "{\"errorCode\":10501}");
stubFor(unaryMethod(TesseractServiceGrpc.getGetQuotePermissionParamMethod())
.willReturn(Status.UNAUTHENTICATED.withCause(new StatusRuntimeException(Status.UNAUTHENTICATED.withDescription("errorMessage"), trailers)))
.nextWillReturn(Status.UNAUTHENTICATED.withDescription("errorMessage").augmentDescription(trailers.toString()))
.nextWillReturn(response(mockResponse)));
Currently it's only possible to verify stubbed method calls. If a call if made to gRPC Mock for a method, which has not a single stub, the request won't get captured and it won't be possible to verify it.
First of all I want to thank you for this simple solution for grpc mocking, it's really useful in unit tests!
But sometimes we would like the grpcmock to be called not directly from tests, but from another service (yep, I'm talking about end-2-end tests for several microservices)
WireMock and mock-server already support running as stateful service in docker, and I'm sure many developers will be happy to get a similar solution for gRPC.
Also, gripmock already supports standalone running in docker, but they don't have a remote client, there is only REST API. Of course, it is possible to implement “WireMock-style” simple client for gripmock,
but first I wanted to ask if you have any plans to do something like that in the future?
Thanks!
How to mock Grpc Method with request with one unknown field?
stubFor(unaryMethod(UserGrpc.getCreateMethod())
.withRequest(UserOuterClass.CreateUserReq.newBuilder()
.setEmail(email)
.setPassword( any() ) <--------- this field?
.build()
)
.willReturn(UserOuterClass.User.newBuilder()
.setId(userId)
.build()
)
);
I tried Mockito's any() etc. It doesn't work
First of all thanks for this library, it's fantastic and exactly what we were looking for. Super easy to use once we got the setup/annotations right.
There is however one strange issue I noticed recently in one of our integration tests:
When the test (Junit 4) specifies a timeout (e.g. via @test(timeout = 5000)), then all calls to the mock server return Code.UNIMPLEMENTED. As soon as I remove the timeout, the test works fine. The timeout value doesn't seem to matter in this case, the test is nowhere close to actually timing out.
I haven't had the time to create a minimal reproducible example yet, but maybe someone has an idea what might be causing this behavior.
Versions:
org.grpcmock:grpcmock:0.5.3
org.grpcmock:grpcmock-spring-boot:0.5.3
I have a service which is based on gRPC. But that having both types of downstreams:
Can we use gRPCMock to stub both endpoints? If yes, please share an example.
When trying to launch tests with gRPC 1.59.0, I have this error - with 1.58.0 everything is fine
Probably it's because of planned ABI breakage in 1.59.0
Class
io.grpc.internal.AbstractManagedChannelImplBuilder
is deleted, and no longer in the class hierarchy of the channel builders:
Looks like the only way to fix that is to bump gRPC version to 1.59.0
io.grpc.ServerProvider: io.grpc.netty.shaded.io.grpc.netty.NettyServerProvider Unable to get public no-arg constructor
java.util.ServiceConfigurationError: io.grpc.ServerProvider: io.grpc.netty.shaded.io.grpc.netty.NettyServerProvider Unable to get public no-arg constructor
at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:586)
at java.base/java.util.ServiceLoader.getConstructor(ServiceLoader.java:679)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1240)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1273)
at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1309)
at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1393)
at io.grpc.ServiceProviders.loadAll(ServiceProviders.java:67)
at io.grpc.ServerRegistry.getDefaultRegistry(ServerRegistry.java:94)
at io.grpc.ServerProvider.provider(ServerProvider.java:42)
at io.grpc.ServerBuilder.forPort(ServerBuilder.java:44)
at org.grpcmock.GrpcMockBuilder.<init>(GrpcMockBuilder.java:32)
at org.grpcmock.GrpcMock.grpcMock(GrpcMock.java:198)
at org.grpcmock.GrpcMock.grpcMock(GrpcMock.java:191)
at org.grpcmock.junit5.GrpcMockExtension.<init>(GrpcMockExtension.java:38)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Caused by: java.lang.NoClassDefFoundError: io/grpc/internal/AbstractServerImplBuilder
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1017)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:862)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:760)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:681)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
at java.base/java.lang.Class.getDeclaredConstructors0(Native Method)
at java.base/java.lang.Class.privateGetDeclaredConstructors(Class.java:3373)
at java.base/java.lang.Class.getConstructor0(Class.java:3578)
at java.base/java.lang.Class.getConstructor(Class.java:2271)
at java.base/java.util.ServiceLoader$1.run(ServiceLoader.java:666)
at java.base/java.util.ServiceLoader$1.run(ServiceLoader.java:663)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
at java.base/java.util.ServiceLoader.getConstructor(ServiceLoader.java:674)
... 27 more
Caused by: java.lang.ClassNotFoundException: io.grpc.internal.AbstractServerImplBuilder
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
Hello. Is there currently any plan to support StubMapping like the equivalence in WireMock?
StubMapping enables storing stub definitions/specifications in plain JSONs, and loading them back to set up all the stubs in the mock server. It opens the window for users without Java skills to set up gRPC stubs easily, and opens another window for GUIed tools to integrate/embed the grpcmock framework in their frameworks.
Response text included "&" will lead the channel is closed.
io.grpc.StatusRuntimeException: UNAVAILABLE: Channel shutdown invoked
I don't confirm where cause the bug in grpcmock.
Hello! Just wanted to say thanks for this library! It's already helping us mocking our gRPC services.
Hi all,
I actually have some problems running my tests with gradle --parallel option. Without it, everything works fine, with it I continuously get
io.grpc.StatusRuntimeException: UNAVAILABLE: No servers found for localhost:62497
at app//io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:262)
at app//io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:243)
at app//io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:156)
Here is how I set my tests
@ExtendWith({MockitoExtension.class, GrpcMockExtension.class})
public class TicketServiceTest implements WithAssertions {
private ManagedChannel frontendChannel;
private ManagedChannel backendChannel;
@BeforeEach
public void setUp() {
frontendChannel = buildManagedChannel();
backendChannel = buildManagedChannel();
val frontendStub = FrontendServiceGrpc.newBlockingStub(frontendChannel);
val backendStub = BackendServiceGrpc.newBlockingStub(backendChannel);
...
}
@AfterEach
void cleanup() {
val channels = List.of(frontendChannel, backendChannel);
channels.forEach(managedChannel -> Optional.ofNullable(managedChannel).ifPresent(ManagedChannel::shutdownNow));
}
private ManagedChannel buildManagedChannel() {
return ManagedChannelBuilder.forAddress("localhost", GrpcMock.getGlobalPort())
.usePlaintext()
.build();
}
}
Do you guys have any idea?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.