package au.com.dius.pact.consumer; import au.com.dius.pact.consumer.dsl.PactDslJsonBody; import au.com.dius.pact.consumer.dsl.PactDslResponse; import au.com.dius.pact.model.MockProviderConfig; import au.com.dius.pact.model.PactSpecVersion; import org.apache.commons.lang3.math.NumberUtils; import org.apache.commons.lang3.time.DateFormatUtils; import org.apache.http.entity.ContentType; import org.jetbrains.annotations.NotNull; import org.json.JSONObject; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Date; import java.util.HashMap; import java.util.Map; import static au.com.dius.pact.consumer.ConsumerPactRunnerKt.runConsumerTest; public class MatchingTest { private static final Logger LOGGER = LoggerFactory.getLogger(MatchingTest.class); private static final String HARRY = "harry"; private static final String HELLO = "/hello"; private static final String TEST_CONSUMER = "test_consumer"; private static final String TEST_PROVIDER = "test_provider"; @Test public void testRegexpMatchingOnBody() { PactDslJsonBody body = new PactDslJsonBody() .stringMatcher("name", "\\w+", HARRY) .stringMatcher("position", "staff|contactor"); PactDslJsonBody responseBody = new PactDslJsonBody() .stringMatcher("name", "\\w+", HARRY); HashMap<String, String> expectedResponse = new HashMap<String, String>(); expectedResponse.put("name", HARRY); runTest(buildPactFragment(body, responseBody, "a test interaction that requires regex matching"), "{\"name\": \"Arnold\", \"position\": \"staff\"}", expectedResponse, HELLO); } @Test public void testMatchingByTypeOnBody() { PactDslJsonBody body = new PactDslJsonBody() .stringType("name") .booleanType("happy") .hexValue("hexCode") .id() .ipAddress("localAddress") .numberValue("age", 100) .numberType("ageAverage", 150.0) .integerType("age2", 200) .timestamp(); PactDslJsonBody responseBody = new PactDslJsonBody(); HashMap expectedResponse = new HashMap(); runTest(buildPactFragment(body, responseBody, "a test interaction that requires type matching"), new JSONObject() .put("name", "Giggle and Hoot") .put("happy", true) .put("hexCode", "abcdef0123456789") .put("id", 1234567890) .put("localAddress", "192.168.0.1") .put("age", 100) .put("ageAverage", 150.0) .put("age2", 200) .put("timestamp", DateFormatUtils.ISO_DATETIME_FORMAT.format(new Date())) .toString(), expectedResponse, HELLO); } @Test public void testRegexpMatchingOnPath() { PactDslResponse fragment = ConsumerPactBuilder .consumer(TEST_CONSUMER) .hasPactWith(TEST_PROVIDER) .uponReceiving("a request to match on path") .matchPath("/hello/[0-9]{4}") .method("POST") .body("{}", ContentType.APPLICATION_JSON) .willRespondWith() .status(200); Map expectedResponse = new HashMap(); runTest(fragment, "{}", expectedResponse, "/hello/1234"); } @Test public void testRegexpMatchingOnHeaders() { PactDslResponse fragment = ConsumerPactBuilder .consumer(TEST_CONSUMER) .hasPactWith(TEST_PROVIDER) .uponReceiving("a request to match on headers") .path(HELLO) .method("POST") .matchHeader("testreqheader", "test.*value", "testreqheadervalue") .body("{}", ContentType.APPLICATION_JSON) .willRespondWith() .status(200) .matchHeader("Location", ".*/hello/[0-9]+", "/hello/1234"); Map expectedResponse = new HashMap(); runTest(fragment, "{}", expectedResponse, HELLO); } @Test public void testRegexCharClassStringGenerator() { PactDslJsonBody numeric = new PactDslJsonBody() .stringMatcher("x", "\\d+"); String val = new JSONObject(numeric.getBody().toString()).getString("x"); Assert.assertTrue("'" + val + "' is not a number", NumberUtils.isDigits(val)); PactDslJsonBody numericWithLimitedRep = new PactDslJsonBody() .stringMatcher("x", "\\d{9}"); val = new JSONObject(numericWithLimitedRep.getBody().toString()).getString("x"); Assert.assertTrue("'" + val + "' is not a number", NumberUtils.isDigits(val)); } @Test public void testRegexpMatchingOnQueryParameters() { PactDslResponse fragment = ConsumerPactBuilder .consumer(TEST_CONSUMER) .hasPactWith(TEST_PROVIDER) .uponReceiving("a request to match on query parameters") .path(HELLO) .method("POST") .matchQuery("a", "\\d+") .matchQuery("b", "\\d+") .matchQuery("c", "[A-Z]") .body("{}", ContentType.APPLICATION_JSON) .willRespondWith() .status(200); Map expectedResponse = new HashMap(); runTest(fragment, "{}", expectedResponse, HELLO + "?a=100&b=200&c=X"); } private void runTest(PactDslResponse pactFragment, final String body, final Map expectedResponse, final String path) { MockProviderConfig config = MockProviderConfig.createDefault(PactSpecVersion.V2); PactVerificationResult result = runConsumerTest(pactFragment.toPact(), config, new PactTestRun() { @Override public void run(@NotNull MockServer mockServer) throws IOException { try { Assert.assertEquals(expectedResponse, new ConsumerClient(config.url()).post(path, body, ContentType.APPLICATION_JSON)); } catch (IOException e) { LOGGER.error(e.getMessage(), e); throw e; } } }); if (result instanceof PactVerificationResult.Error) { throw new RuntimeException(((PactVerificationResult.Error)result).getError()); } Assert.assertEquals(PactVerificationResult.Ok.INSTANCE, result); } private PactDslResponse buildPactFragment(PactDslJsonBody body, PactDslJsonBody responseBody, String description) { return ConsumerPactBuilder .consumer(TEST_CONSUMER) .hasPactWith(TEST_PROVIDER) .uponReceiving(description) .path(HELLO) .method("POST") .body(body) .willRespondWith() .status(200) .body(responseBody); } }