Skip to content

Commit

Permalink
Merge pull request #18 from kyle-winkelman/aggregate
Browse files Browse the repository at this point in the history
Reuse common WireMock components to create aggregate MatchResult.
  • Loading branch information
nilwurtz authored Dec 14, 2023
2 parents e5d028f + d7cd2ac commit 6279a0c
Show file tree
Hide file tree
Showing 15 changed files with 1,043 additions and 240 deletions.
106 changes: 67 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ GraphqlBodyMatcherは[WireMock](https://wiremock.org/)の拡張で、GraphQLの
## Overview 📖

- In addition to handling whitespaces, the extension sorts and normalizes queries. The GraphQL parsing and normalizing is handled by `graphql-java`.
- Beyond just queries, it also compares variables. For the comparison of JSON variables, `org.json.JSONObject.similar` is employed. It's important to note that the order of arrays must match.
- Beyond just queries, it also compares variables. For the comparison of JSON variables, [EqualToJsonPattern](https://github.com/wiremock/wiremock/blob/3.3.1/src/main/java/com/github/tomakehurst/wiremock/matching/EqualToJsonPattern.java) is used. It's important to note that the order of arrays must match.

For a comprehensive understanding of our matching logic and details on our match strategy, please refer to our [MatchStrategy documentation](./docs/MatchStrategy.md).

Expand Down Expand Up @@ -47,49 +47,69 @@ dependencies {


## Code Examples 💡
Here are some code examples to get started:
```kotlin
import io.github.nilwurtz.GraphqlBodyMatcher
Here are some code examples to get started.

WireMock.stubFor(
WireMock.post(WireMock.urlEqualTo("/graphql"))
.andMatching(GraphqlBodyMatcher.withRequestJson("""{"query": "{ hero { name }}"}"""))
.willReturn(WireMock.ok())
)
```
```java Java
import com.github.tomakehurst.wiremock.client.WireMock;
import io.github.nilwurtz.GraphqlBodyMatcher;

import java.util.Map;

The GraphQL query is expected inside the `"query"` key and variables within the `"variables"` key.
var expectedQuery = """
query HeroInfo($id: Int) {
hero(id: $id) {
name
}
}
""";
var expectedVariables = Map.of("id", 1);

WireMock.stubFor(WireMock.post(WireMock.urlEqualTo("/graphql"))
.andMatching(GraphqlBodyMatcher.extensionName, GraphqlBodyMatcher.parameters(expectedQuery, expectedVariables))
.willReturn(WireMock.okJson("""
{
"data": {
"hero": {
"name": "example"
}
}
}""")));
```
```kotlin Kotlin
import com.github.tomakehurst.wiremock.client.WireMock
import io.github.nilwurtz.GraphqlBodyMatcher

```kotlin
val expectedQuery = """
query HeroInfo($id: Int) {
hero(id: $id) {
query HeroInfo(${'$'}id: Int) {
hero(id: ${'$'}id) {
name
}
}
""".trimIndent()

val expectedVariables = """
{
"id": 1
}
""".trimIndent()

val expectedJson = """
{
"query": "$expectedQuery",
"variables": $expectedVariables
}
""".trimIndent()
val expectedVariables = mapOf("id" to 1)

WireMock.stubFor(
WireMock.post(WireMock.urlEqualTo("/graphql"))
.andMatching(GraphqlBodyMatcher.withRequestJson(expectedJson))
.willReturn(WireMock.ok())
.andMatching(GraphqlBodyMatcher.extensionName, GraphqlBodyMatcher.parameters(expectedQuery, expectedVariables))
.willReturn(
WireMock.okJson("""
{
"data": {
"hero": {
"name": "example"
}
}
}
""".trimIndent()
)
)
)
```

The `withRequestQueryAndVariables` method has been deprecated from version 0.6.0 onwards. Please use `withRequestJson` instead.
As we head towards a 1.0 release, we are focusing on supporting both the WireMock standalone and the WireMock Java API
with the same paradigm. This is done through the use of `WireMock.requestMatching()` or `MappingBuilder#andMatching()`.
To that end, the `withRequestQueryAndVariables` method has been deprecated from version 0.6.0 onwards and
`withRequestJson` and `withRequest` methods have been deprecated from version 0.9.0 onwards.

## Running with a Remote Wiremock Server 🌍

Expand All @@ -112,27 +132,35 @@ docker run -it --rm \
```dockerfile
FROM wiremock/wiremock:latest
COPY ./wiremock-graphql-extension-0.8.1-jar-with-dependencies.jar /var/wiremock/extensions/wiremock-graphql-extension-0.8.1-jar-with-dependencies.jar
CMD ["--extensions", "io.github.nilwurtz.GraphqlBodyMatcher"]
```

### Client-side (Test) Configuration

NOTE: When using a Remote Wiremock Server, you're requested to manage everything within a single JSON format.

```kotlin
```java Java
import com.github.tomakehurst.wiremock.client.WireMock;
import io.github.nilwurtz.GraphqlBodyMatcher;

import static com.github.tomakehurst.wiremock.client.WireMock.*;

public registerGraphQLWiremock(String query, String response) {
WireMock(8080).register(
post(urlPathEqualTo(endPoint))
.andMatching(GraphqlBodyMatcher.extensionName, GraphqlBodyMatcher.parameters(query))
.willReturn(okJson(response)));
}
```
```kotlin Kotlin
import com.github.tomakehurst.wiremock.client.WireMock
import com.github.tomakehurst.wiremock.client.WireMock.*
import io.github.nilwurtz.GraphqlBodyMatcher

fun registerGraphQLWiremock(json: String) {
fun registerGraphQLWiremock(query: String, response: String) {
WireMock(8080).register(
post(urlPathEqualTo(endPoint))
.andMatching(GraphqlBodyMatcher.extensionName, GraphqlBodyMatcher.withRequest(json))
.willReturn(
aResponse()
.withStatus(200)
)
)
.andMatching(GraphqlBodyMatcher.extensionName, GraphqlBodyMatcher.parameters(query))
.willReturn(okJson(response)))
}
```

Expand Down
97 changes: 83 additions & 14 deletions examples/testcontainers-java/src/test/java/TestSample.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import com.github.tomakehurst.wiremock.client.WireMock;
import io.github.nilwurtz.GraphqlBodyMatcher;
import org.junit.jupiter.api.DisplayName;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
Expand All @@ -12,12 +11,21 @@
import java.net.http.HttpResponse;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.*;

@Testcontainers
public class TestSample {

private static final String RESPONSE = """
{
"data": {
"id": 1,
"name": "test"
}
}
""";
@Container
private static final WireMockContainer wiremockContainer = new WireMockContainer(
DockerImageName.parse(WireMockContainer.OFFICIAL_IMAGE_NAME)
Expand All @@ -40,30 +48,91 @@ public void testRunning() {
}

@Test
@DisplayName("Matches if GraphQL query is semantically equal to the request")
public void testGraphql() throws IOException, InterruptedException {
public void testMatches() throws IOException, InterruptedException {
var query = """
query {
name
id
}
""";
new WireMock(wiremockContainer.getPort()).register(
WireMock.post(WireMock.urlEqualTo("/graphql"))
.andMatching(
GraphqlBodyMatcher.extensionName,
GraphqlBodyMatcher.parameters(query))
.willReturn(WireMock.okJson(RESPONSE)));;


var client = HttpClient.newHttpClient();
var request = java.net.http.HttpRequest.newBuilder()
.uri(java.net.URI.create(wiremockContainer.getBaseUrl() + "/graphql"))
.POST(java.net.http.HttpRequest.BodyPublishers.ofString("""
{ "query": "query { id name }" }"""))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());

assertEquals(200, response.statusCode());
assertEquals(RESPONSE, response.body());
}

@Test
public void testMatchesVariables() throws IOException, InterruptedException {
var query = """
query {
name
id
}
""";
var variables = Map.of("id", 1);
new WireMock(wiremockContainer.getPort()).register(
WireMock.post(WireMock.urlEqualTo("/graphql"))
.andMatching(
GraphqlBodyMatcher.extensionName,
GraphqlBodyMatcher.parameters(query, variables)
)
.willReturn(WireMock.okJson(RESPONSE)));


var client = HttpClient.newHttpClient();
var request = java.net.http.HttpRequest.newBuilder()
.uri(java.net.URI.create(wiremockContainer.getBaseUrl() + "/graphql"))
.POST(java.net.http.HttpRequest.BodyPublishers.ofString("""
{"query": "query { id name }", "variables": {"id": 1}}"""))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());

assertEquals(200, response.statusCode());
assertEquals(RESPONSE, response.body());
}

@Test
public void testMatchesVariablesAndOperationName() throws IOException, InterruptedException {
var query = """
query {
name
id
}
""";
var variables = Map.of("id", 1);
var operationName = "operationName";
new WireMock(wiremockContainer.getPort()).register(
WireMock.post(WireMock.urlEqualTo("/graphql"))
.andMatching(
GraphqlBodyMatcher.extensionName,
GraphqlBodyMatcher.withRequest(
"{ \"query\": \"{ query { name id }}\" }"
)
GraphqlBodyMatcher.parameters(query, variables, operationName)
)
.willReturn(
WireMock.aResponse()
.withBody("{\"data\": {\"id\": 1, \"name\": \"test\"}}")
));
.willReturn(WireMock.okJson(RESPONSE)));


var client = HttpClient.newHttpClient();
var request = java.net.http.HttpRequest.newBuilder()
.uri(java.net.URI.create(wiremockContainer.getBaseUrl() + "/graphql"))
.POST(java.net.http.HttpRequest.BodyPublishers.ofString("{ \"query\": \"{ query { id name }}\" }"))
.POST(java.net.http.HttpRequest.BodyPublishers.ofString("""
{"query": "query { id name }", "variables": {"id": 1}, "operationName": "operationName"}"""))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());

assertEquals(200, response.statusCode());
assertEquals("{\"data\": {\"id\": 1, \"name\": \"test\"}}", response.body());
assertEquals(RESPONSE, response.body());
}
}
Loading

0 comments on commit 6279a0c

Please sign in to comment.