How to proxy (almost) all requests through WireMock? - java

I have a following problem: There's a service I'm mocking (for integration tests) using a docker container I run on a specific port. Because the mock service has not been updated (I don't own the code) a few endpoints that exist in the real service are not supported there.
I'm considering forking the repository and adding them myself, but other solution I'm trying is proxying all the requests via a WireMock server and stubbing only the missing endpoints. Is there a simple way to achieve this? It looks like I'd need to proxy every rest method separately, like this:
WireMockServer wireMockServer = new WireMockServer(8080);
wireMockServer.start();
// Proxy to the standalone mock server:
// GET
wireMockServer.stubFor(get(anyUrl())
.atPriority(10)
.willReturn(aResponse().proxiedFrom("http://localhost:8081/the-standalone-service")));
// POST
wireMockServer.stubFor(get(anyUrl())
.atPriority(10)
.willReturn(aResponse().proxiedFrom("http://localhost:8081/the-standalone-service")));
// PUT
wireMockServer.stubFor(put(anyUrl())
.atPriority(10)
.willReturn(aResponse().proxiedFrom("http://localhost:8081/the-standalone-service")));
...
// Overwrite only selected endpoints:
wireMockServer.stubFor(get(urlEqualTo("/the-service/users/"))
.atPriority(1)
.willReturn(aResponse()
.withHeader("Content-Type", "application/json")
.withBody("...")));
...

It took me less time to find an answer than writing the question, there's a WireMock.any() method matching all request methods, so this should suffice:
// Proxy to the standalone mock server:
wireMockServer.stubFor(WireMock.any(anyUrl())
.atPriority(10)
.willReturn(aResponse().proxiedFrom("http://localhost:8081/the-standalone-service")));
I'll confirm if it works later today.

Related

How to verify a wiremock service get some calls

I am doing a functional testing of a service A. The function is triggered by an api call 1 from service B and then at last respond (send another api call 2) to the service B. Therefore, the plan is to wiremock the service B and make a call 1 and then verify that it get a api call 2 request back.
We use wiremock in the docker compose file to simulate the service B as below:
service-b:
image: ***/wiremock-service-b
ports:
- "8081:8081"
volumes:
- ./wiremock/service-b/mappings/:/home/wiremock/mappings/
Is there any way I can get THIS service B wiremock instance (deployed in docker) using java code and triggered a call 1 and then verify a call 2 request coming back? Please help. Thanks.
If the docker compose is running, you can configure the default static WireMock client to use it as so:
import static com.github.tomakehurst.wiremock.client.WireMock.*;
configureFor("localhost", 8081);
as you are port forwarding to 8081.
See WireMock > Java configuration for further details.
You can then verify that service B was called as usual:
verify(postRequestedFor(urlEqualTo("/verify/this"))
.withHeader("Content-Type", equalTo("text/xml")));
See Wiremock > Verifying for further details.
It seems like you are mixing two approaches on your tests. I assume you are doing an integration test:
When using Wiremock, you don't need to launch your service in a Docker container. The purpose of Wiremock, is to simulate the response you receive when you call the service you are mocking. You don't really call the service in this case.
With the second approach you can use a Docker container with TestContainer. In this case, to check whether the service is called you have to test the response and check if this is your expected results. First the service (in your container) you want to call have be to exposed by an API, then in your service you are testing, you call the service with TestRestemplate or WebTestClient.
A sample code will be like this:
#Test
void integrationTest_For_Status_200() {
webTestClient.post()
.uri("THE_SERVICE_URL")
.accept(MediaType.APPLICATION_JSON)
.bodyValue(personDto)
.exchange()
.expectStatus().isOk()
.expectBody(Response.class)
.value(response -> assertAll(
() -> assertThat(response.getStatusValue()).isEqualTo(HttpStatus.OK.value()),
() -> assertThat(response.getStatusReasonPhrase()).isEqualTo(HttpStatus.OK.getReasonPhrase()),
() -> assertThat(response.getDescription()).isEqualTo(category.getDescription())
));
}
I would suggest those links bellow that will explain the approach of integration tests:
https://rieckpil.de/guide-to-springboottest-for-spring-boot-integration-tests/
https://www.freecodecamp.org/news/integration-testing-using-junit-5-testcontainers-with-springboot-example/
https://docs.spring.io/spring-framework/docs/current/reference/html/testing.html#webtestclient-tests

Quarkus GraphQL Client with Keycloak

I'm trying this for days right now and I'm not sure if i missed something.
I have a Quarkus GraphQL Service , like here : https://quarkus.io/guides/smallrye-graphql
And I have setup Keycloak to secure it.
Now I wanted to create a client with Qute and GraphQL Smallrye client like here : https://quarkus.io/guides/smallrye-graphql-client
The client can connect to the service, but I always get an "Data Fetching Error: io.quarkus.security.UnauthorizedException".
It seems like the GraphQL client is not sending the headers correctly or it doesn't send any ...
Does anyone know how I can tell the client to send the Authorization header from keycloak with every call?
PS: I tested it with a short react frontend and there it's working, so it seems to be an graphql client issue with the headers... Some ideas?
Not sure if you're using a dynamic or typesafe client, so I'll describe both.
For both types, if you have a key that doesn't change during the life of the application, you can configure that by adding a configuration property like this:
quarkus.smallrye-graphql-client.CLIENT_NAME.header.HEADER_NAME=HEADER_VALUE
(see https://quarkus.io/guides/all-config#quarkus-smallrye-graphql-client_quarkus-smallrye-graphql-client-smallrye-graphql-client)
If the value can change over time, I would probably recommend using the programmatic builder instead of using a statically configured client, like this:
DynamicGraphQLClientBuilder.newBuilder()
.header("KEY", "VALUE") // obtain the correct value from Keycloak and pass it here
....
and build a new client instance if the value changes.
For typesafe clients, an annotation-based way is described in https://smallrye.io/smallrye-graphql/1.4.3/typesafe-client-headers/
I don't know much about Keycloak though so I can't comment on the way how you obtain the header value from it.
Let me know some of this works for you
There doesn't seem to be a dynamic way of adding keycloak headers to the call.
I found a solution, to at least work as long as the token is valid.
For this I'm using a Client Class, which has an Interface Object of the GraphQL client and injects the header inside the constructor.I will need to add some code to renew the token, but it's enough to work with it right now :)
For those who want some code:
#Singleton
public class Client {
public IClient client;
public Client(JsonWebToken accessToken) {
client = TypesafeGraphQLClientBuilder.newBuilder()
.header("Authorization", "Bearer " + accessToken.getRawToken())
.build(IClient.class);
}
}
With this the Client can be build like shown at the Quarkus Guides :)

How to handle real API URL via mock server?

I have a real API (https://profiles.production.service/api/person). And want to mock it using MockServer.
I'm using JUnit 5 in my integration test:
#Rule
val mockServer = MockServerContainer(DockerImageName.parse("jamesdbloom/mockserver:mockserver-5.11.2"))
mockServer.start()
....
MockServerClient("profiles.production.service", mockServer.serverPort)
.`when`(
request()
.withPath("/api/person")
.withQueryStringParameter("name", "peter")
)
.respond(
response()
.withBody("Peter the person!")
)
But actually got error:
org.mockserver.client.SocketConnectionException: Unable to resolve host profiles.production.service/<unresolved>:55070
How can I fix it?
This answer arrives too late for sure. But I am writing, just in case others come here and have a similar problem.
Looking at the documentation of the mockserver you can see an example that would make it work. Your code would need to change to:
MockServerClient(mockServer.getHost(), mockServer.getServerPort())
MockServerContainer is a docker image running on its own. So it will have a different URL than the server you need to mock.
If the problem you have is that you have hardcoded the server name on your class, then you would need to change that class. You will need to inject the server name. In your case
"https://%s:%d/api/person".format(mockServer.getHost(), mockServer.getServerPort())

How to make Spring Cloud Contract reset WireMock before or after each test

We are writing a Spring Boot application and use the Cloud Contract WireMock support to stub a backing service. Our test class is annotated like so:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
#AutoConfigureWireMock(port = 0)
public class Tests...
This works fine except for one thing: We found out that Spring Cloud does not seem to reset WireMock, in particular delete stubs, in between tests so that tests are not isolated properly. Of course, you can accomplish this yourself with a #Before method containing a reset(), but we wonder whether this is intentional. Is there an option that we have overlooked or an additional annotation one has to use?
After all, it is not possible to define stubs in a #BeforeClass method that would be gone if a reset would always be performed, so we wonder what speaks against doing it out of the box?
Configure Spring Boot property:
wiremock:
reset-mappings-after-each-test: true
ref: https://github.com/spring-cloud/spring-cloud-contract/commit/67119e62f6b30da56b06aade87ec3ba61de7fd24
I ended up injecting WireMockServer and running wireMockServer.resetAll() in #BeforeEach.
The WireMock server can be reset at any time, removing all stub mappings and deleting the request log. If you’re using either of the JUnit rules this will happen automatically at the start of every test case. However you can do it yourself via a call to WireMock.reset() in Java or sending a POST request with an empty body to http://<host>:<port>/__admin/reset.
To reset just the stub mappings leaving the request log intact send a DELETE to http://<host>:<port>/__admin/mappings.
Hope this is useful.

How do I unit test code which calls the Jersey Client API?

I wrote code which calls the Jersey client API which in turn calls a web service which is out of my control. I do not want my unit test to call the actual web service.
What is the best approach for writing a unit test for code which calls the Jersey client API? Should I use the Jersey server API to write a JAX-RS web service and then use the Jersey Test Framework for the unit test? Or should I mock out the Jersey web service calls? I have access to JMock. Or should I try another approach?
During my research, I found this discussion describing various options, but I did find a complete solution. Are there any code examples available showing a suggested JUnit approach? I could not find any in the Jersey documentation.
Here is the relevant source code:
public String getResult(URI uri) throws Exception {
// error handling code removed for clarity
ClientConfig clientConfig = new DefaultClientConfig();
Client client = Client.create(clientConfig);
WebResource service = client.resource(uri);
String result = service.accept(accept).get(String.class);
return result;
}
Here are examples of test code I would like to pass. I would like to test (1) passing in a valid URI and getting a valid string back and (2) passing in an invalid (for whatever reason -- unreachable or unauthorized) URI and getting an exception back.
#Test
public void testGetResult_ValidUri() throws Exception {
String xml = retriever.getResult(VALID_URI);
Assert.assertFalse(StringUtils.isBlank(xml));
}
#Test(expected = IllegalArgumentException.class)
public void testGetResult_InvalidUri() throws Exception {
retriever.getResult(INVALID_URI);
}
Everything above is the simple description of what my code does. In reality, there is a layer on top of that that accepts two URIs, first tries calling the first URI, and if that URI fails then it tries calling the second URI. I would like to have unit tests covering (1) the first URI succeeds, (2) the first URI fails and the second URI succeeds, and (3) both URIs fail. This code is sufficiently complex that I want to test these different scenarios using JUnit, but to do this I either need to run actual stand-in web services or mock out the Jersey client API calls.
Try to use Mockito or Easymock for mocking service calls. You need to mock only these methods which are actually used - no need to mock every method. You can creat mock object for WebResource class, then mock accept method call.
In #BeforeClass/#Before JUnit test method write something like (Mockito example)
WebResource res = mock(WebResource.class);
when(res.accept(something)).thenReturn(thatWhatYouWant);
Then in your tests you can use res object as if it was real object and call mock method on it. Instead of returning value you can also throw exceptions. Mockito is pretty cool.
Typically what you are really after is "does the way I use the Jersey Client DSL produce a request to the correct URL with the correct payload and URL parameters". Testing this with Mockito is really verbose and the setup code will usually end up looking something like this:
when(authentication.queryParam(eq("sa"), anyBoolean())).thenReturn(testAuthentication);
when(testAuthentication.resolveTemplate("channel", "smf")).thenReturn(testAuthentication);
when(testAuthentication.request(
MediaType.APPLICATION_JSON_TYPE)).thenReturn(mockRequestBuilder);
when(mockRequestBuilder.post(any(Entity.class))).thenReturn(mockResponse);
when(mockResponse.readEntity(ResponseWrapper.class)).thenReturn(successfulAuthResponse());
And this is basically just for a single REST request. It's overly verbose, and instead of testing the hoped outcome you are just replicating the steps you think are correct in using the Jersey Client DSL.
Instead of the above, I would aim for mocking a simple service. For this I've used WireMock which starts a Jetty server and where I can stub things like "expect a request to this URL, respond with this message and verify that the payload is this".
I know this is edging on an integration test and it is a bit slower than just using Mockito but I value testing the real outcome and I value the readability of the tests way more in this case.
Setup for a WireMock based Jersey Client test looks something like this:
#Test
public void exactUrlOnly() {
stubFor(get(urlEqualTo("/some/thing"))
.willReturn(aResponse()
.withHeader("Content-Type", "text/plain")
.withBody("Hello world!")));
assertThat(testClient.get("/some/thing").statusCode(), is(200));
assertThat(testClient.get("/some/thing/else").statusCode(), is(404));
}
Just implement a work-alike service and in your unit test setup start the service using HttpServerFactory.

Categories

Resources