Skip to content

Commit

Permalink
Implemented wildcards for map keys in the Java DSL #313
Browse files Browse the repository at this point in the history
  • Loading branch information
Ronald Holshausen committed Sep 10, 2016
1 parent b483572 commit 3acffb5
Show file tree
Hide file tree
Showing 10 changed files with 321 additions and 100 deletions.
2 changes: 1 addition & 1 deletion pact-jvm-consumer-groovy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ withBody {
}
```

### Matching any key in a map (3.3.1+)
### Matching any key in a map (3.3.1/2.5.0+)

The DSL has been extended for cases where the keys in a map are IDs. For an example of this, see
[#313](https:/DiUS/pact-jvm/issues/131). In this case you can use the `keyLike` method, which takes an
Expand Down
34 changes: 34 additions & 0 deletions pact-jvm-consumer-junit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,40 @@ For example:
.body(PactDslJsonRootValue.integerType())
```

#### Matching any key in a map (3.3.1/2.5.0+)

The DSL has been extended for cases where the keys in a map are IDs. For an example of this, see
[#313](https:/DiUS/pact-jvm/issues/131). In this case you can use the `eachKeyLike` method, which takes an
example key as a parameter.

For example:

```java
DslPart body = new PactDslJsonBody()
.object("one")
.eachKeyLike("001", PactDslJsonRootValue.id(12345L)) // key like an id mapped to a matcher
.closeObject()
.object("two")
.eachKeyLike("001-A") // key like an id where the value is matched by the following example
.stringType("description", "Some Description")
.closeObject()
.closeObject()
.object("three")
.eachKeyMappedToAnArrayLike("001") // key like an id mapped to an array where each item is matched by the following example
.id("someId", 23456L)
.closeObject()
.closeArray()
.closeObject();

```

For an example, have a look at [WildcardKeysTest](src/test/java/au/com/dius/pact/consumer/WildcardKeysTest.java).

**NOTE:** The `eachKeyLike` method adds a `*` to the matching path, so the matching definition will be applied to all keys
of the map if there is not a more specific matcher defined for a particular key. Having more than one `eachKeyLike` condition
applied to a map will result in only one being applied when the pact is verified (probably the last).


### Matching on paths (version 2.1.5+)

You can use regular expressions to match incoming requests. The DSL has a `matchPath` method for this. You can provide
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package au.com.dius.pact.consumer;

import au.com.dius.pact.consumer.dsl.DslPart;
import au.com.dius.pact.consumer.dsl.PactDslJsonBody;
import au.com.dius.pact.consumer.dsl.PactDslJsonRootValue;
import au.com.dius.pact.consumer.dsl.PactDslWithProvider;
import au.com.dius.pact.model.PactFragment;
import com.google.common.collect.Sets;
import groovy.json.JsonSlurper;
import org.apache.http.client.fluent.Request;
import org.junit.Rule;
import org.junit.Test;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.is;

public class WildcardKeysTest {

private static final String APPLICATION_JSON = "application/json";

@Rule
public PactProviderRule provider = new PactProviderRule("WildcardKeysProvider", "localhost", 8081, this);

@Pact(provider="WildcardKeysProvider", consumer="WildcardKeysConsumer")
public PactFragment createFragment(PactDslWithProvider builder) {
DslPart body = new PactDslJsonBody()
.eachLike("articles")
.eachLike("variants")
.eachKeyMappedToAnArrayLike("001")
.eachLike("bundles")
.eachKeyLike("001-A")
.stringType("description", "Some Description")
.eachLike("referencedArticles")
.id("bundleId", 23456L)
.eachKeyLike("001-A-1", PactDslJsonRootValue.id(12345L))
.closeObject()
.closeArray()
.closeObject()
.closeObject()
.closeArray()
.closeObject()
.closeArray()
.closeObject()
.closeArray()
.closeObject()
.closeArray();

PactFragment pactFragment = builder
.uponReceiving("a request for an article")
.path("/")
.method("GET")
.willRespondWith()
.status(200)
.body(body)
.toFragment();

Map<String, Map<String, Object>> matchingRules = pactFragment.interactions().head().getResponse().getMatchingRules();
MatcherTestUtils.assertResponseMatcherKeysEqualTo(pactFragment,
"$.body.articles",
"$.body.articles[*].variants",
"$.body.articles[*].variants[*].*",
"$.body.articles[*].variants[*].*[*].bundles",
"$.body.articles[*].variants[*].*[*].bundles[*].*.description",
"$.body.articles[*].variants[*].*[*].bundles[*].*.referencedArticles",
"$.body.articles[*].variants[*].*[*].bundles[*].*.referencedArticles[*].*",
"$.body.articles[*].variants[*].*[*].bundles[*].*.referencedArticles[*].bundleId"
);

return pactFragment;
}

@Test
@PactVerification("WildcardKeysProvider")
public void runTest() throws IOException {
String result = Request.Get("http://localhost:8081/")
.addHeader("Accept", APPLICATION_JSON)
.execute().returnContent().asString();
Map<String, Object> body = (Map<String, Object>) new JsonSlurper().parseText(result);

assertThat(body, hasKey("articles"));
List articles = (List) body.get("articles");
assertThat(articles.size(), is(1));
Map<String, Object> article = (Map<String, Object>) articles.get(0);
assertThat(article, hasKey("variants"));
List variants = (List) article.get("variants");
assertThat(variants.size(), is(1));
Map<String, Object> variant = (Map<String, Object>) variants.get(0);
assertThat(variant.keySet(), is(equalTo(Sets.newHashSet("001"))));
List variant001 = (List) variant.get("001");
assertThat(variant001.size(), is(1));
Map<String, Object> firstVariant001 = (Map<String, Object>) variant001.get(0);
assertThat(firstVariant001, hasKey("bundles"));
List bundles = (List) firstVariant001.get("bundles");
assertThat(bundles.size(), is(1));
Map<String, Object> bundle = (Map<String, Object>) bundles.get(0);
assertThat(bundle.keySet(), is(equalTo(Sets.newHashSet("001-A"))));
Map<String, Object> bundle001A = (Map<String, Object>) bundle.get("001-A");
assertThat(bundle001A.get("description").toString(), is("Some Description"));
assertThat(bundle001A, hasKey("referencedArticles"));
List referencedArticles = (List) bundle001A.get("referencedArticles");
assertThat(referencedArticles.size(), is(1));
Map<String, Object> referencedArticle = (Map<String, Object>) referencedArticles.get(0);
assertThat(referencedArticle, hasKey("bundleId"));
assertThat(referencedArticle.get("bundleId").toString(), is("23456"));
}
}
33 changes: 33 additions & 0 deletions pact-jvm-consumer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,39 @@ This generated the following JSON:

and will be able to match all coordinates regardless of the number of coordinates.

#### Matching any key in a map (3.3.1/2.5.0+)

The DSL has been extended for cases where the keys in a map are IDs. For an example of this, see
[#313](https:/DiUS/pact-jvm/issues/131). In this case you can use the `eachKeyLike` method, which takes an
example key as a parameter.

For example:

```java
DslPart body = new PactDslJsonBody()
.object("one")
.eachKeyLike("001", PactDslJsonRootValue.id(12345L)) // key like an id mapped to a matcher
.closeObject()
.object("two")
.eachKeyLike("001-A") // key like an id where the value is matched by the following example
.stringType("description", "Some Description")
.closeObject()
.closeObject()
.object("three")
.eachKeyMappedToAnArrayLike("001") // key like an id mapped to an array where each item is matched by the following example
.id("someId", 23456L)
.closeObject()
.closeArray()
.closeObject();

```

For an example, have a look at [WildcardKeysTest](src/test/java/au/com/dius/pact/consumer/WildcardKeysTest.java).

**NOTE:** The `eachKeyLike` method adds a `*` to the matching path, so the matching definition will be applied to all keys
of the map if there is not a more specific matcher defined for a particular key. Having more than one `eachKeyLike` condition
applied to a map will result in only one being applied when the pact is verified (probably the last).

### Matching on paths (version 2.1.5+)

You can use regular expressions to match incoming requests. The DSL has a `matchPath` method for this. You can provide
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@ public abstract class DslPart {
private static final String MATCH = "match";

protected final DslPart parent;
protected final String root;
protected final String rootPath;
protected final String rootName;
protected Map<String, Map<String, Object>> matchers = new HashMap<String, Map<String, Object>>();
protected boolean closed = false;

public DslPart(DslPart parent, String root) {
public DslPart(DslPart parent, String rootPath, String rootName) {
this.parent = parent;
this.root = root;
this.rootPath = rootPath;
this.rootName = rootName;
}

public DslPart(String root) {
public DslPart(String rootPath, String rootName) {
this.parent = null;
this.root = root;
this.rootPath = rootPath;
this.rootName = rootName;
}

protected abstract void putObject(DslPart object);
Expand Down
Loading

0 comments on commit 3acffb5

Please sign in to comment.