From 9db71680451378d2f72493bc8c1c4fc1eaf6f7cf Mon Sep 17 00:00:00 2001 From: Heiko Braun Date: Fri, 4 Dec 2015 10:11:06 +0100 Subject: [PATCH] Added an example for consumer driven contracts commit 7f8b0c57480b86048692c2e15f2538224defdb8a Author: Heiko Braun Date: Fri Dec 4 10:09:40 2015 +0100 Added a readme for the consumer driven contracts commit cb977753f7b82944319bb42e738d9c44e33cb8cf Author: Heiko Braun Date: Fri Dec 4 09:44:37 2015 +0100 Group pact examples in custom module commit 6c32fa501b7023d547b80064e70ebc78d08be592 Author: Heiko Braun Date: Fri Dec 4 09:44:22 2015 +0100 Cleanup pact examples commit 9c68fbf83da18e875cd10dd30fff785724c4ce2e Author: Heiko Braun Date: Fri Dec 4 09:35:23 2015 +0100 first roundtrip example commit a3b91e60bca07713eb50e43771e367162858dd0f Author: Heiko Braun Date: Thu Dec 3 17:24:04 2015 +0100 Simplified pact API usage commit 5da28fb9c14ada142db2108b02e3bdbfff24cb71 Author: Heiko Braun Date: Thu Dec 3 15:31:50 2015 +0100 Added a consumer contract test example commit e1bfdd8f389bc48bc5857e2d053b3b6fc22b08f8 Author: Heiko Braun Date: Thu Dec 3 15:10:40 2015 +0100 Added contract based test example --- .gitignore | 2 + jaxrs/contract-based-testing/README.md | 100 +++++++++++++++ .../jaxrs-consumer/pom.xml | 88 ++++++++++++++ .../wildfly/swarm/it/jaxrs/ConsumerTest.java | 54 ++++++++ .../swarm/it/jaxrs/ProviderClient.java | 28 +++++ .../swarm/examples/jaxrs/MyApplication.java | 14 +++ .../swarm/examples/jaxrs/MyResource.java | 19 +++ .../jaxrs-provider/pom.xml | 115 ++++++++++++++++++ .../swarm/it/jaxrs/JAXRSApplicationIT.java | 26 ++++ .../swarm/examples/jaxrs/MyApplication.java | 14 +++ .../swarm/examples/jaxrs/MyResource.java | 26 ++++ .../src/pacts/MyConsumer-MyProvider.json | 33 +++++ jaxrs/contract-based-testing/pom.xml | 30 +++++ jaxrs/pom.xml | 1 + 14 files changed, 550 insertions(+) create mode 100644 jaxrs/contract-based-testing/README.md create mode 100644 jaxrs/contract-based-testing/jaxrs-consumer/pom.xml create mode 100644 jaxrs/contract-based-testing/jaxrs-consumer/src/it/java/org/wildfly/swarm/it/jaxrs/ConsumerTest.java create mode 100644 jaxrs/contract-based-testing/jaxrs-consumer/src/it/java/org/wildfly/swarm/it/jaxrs/ProviderClient.java create mode 100644 jaxrs/contract-based-testing/jaxrs-consumer/src/main/java/org/wildfly/swarm/examples/jaxrs/MyApplication.java create mode 100644 jaxrs/contract-based-testing/jaxrs-consumer/src/main/java/org/wildfly/swarm/examples/jaxrs/MyResource.java create mode 100644 jaxrs/contract-based-testing/jaxrs-provider/pom.xml create mode 100644 jaxrs/contract-based-testing/jaxrs-provider/src/it/java/org/wildfly/swarm/it/jaxrs/JAXRSApplicationIT.java create mode 100644 jaxrs/contract-based-testing/jaxrs-provider/src/main/java/org/wildfly/swarm/examples/jaxrs/MyApplication.java create mode 100644 jaxrs/contract-based-testing/jaxrs-provider/src/main/java/org/wildfly/swarm/examples/jaxrs/MyResource.java create mode 100644 jaxrs/contract-based-testing/jaxrs-provider/src/pacts/MyConsumer-MyProvider.json create mode 100644 jaxrs/contract-based-testing/pom.xml diff --git a/.gitignore b/.gitignore index 25c89884b..61a292dba 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ build/ # verify logs verify.log log +jaxrs/.DS_Store +.DS_Store diff --git a/jaxrs/contract-based-testing/README.md b/jaxrs/contract-based-testing/README.md new file mode 100644 index 000000000..351e98cf3 --- /dev/null +++ b/jaxrs/contract-based-testing/README.md @@ -0,0 +1,100 @@ +# Contract based testing example + +This is an example that demonstrates how consumer driven contracts can be used to verify the contract between a service consumer and a service provider. + +If you are not familiar with contract based testing and consumer driven tests in particular, we recommend the excellent Thoughtworks article, that explains the ideas in great detail: http://martinfowler.com/articles/consumerDrivenContracts.html + +## Example Layout + +The example breaks into two parts: + +**Service consumer part** + +The consumer verifies it's own service interaction patterns against a mock service as part of it's unit or integration test runs (See `ConsumerTest.java`). + +Upon successful completion of the consumer tests, a consumer contract definition is created: + +``` +{ + "provider": { + "name": "MyProvider" + }, + "consumer": { + "name": "MyConsumer" + }, + "interactions": [ + { + "providerState": "Consumer is FOOBAR", + "description": "A request to say Howdy", + "request": { + "method": "POST", + "path": "/", + "headers": { + "client-name": "FOOBAR" + } + }, + "response": { + "status": 200, + "body": "Howdy FOOBAR" + } + } + ], + "metadata": { + "pact-specification": { + "version": "2.0.0" + }, + "pact-jvm": { + "version": "3.2.0" + } + } +} +``` +(Taken from `jaxrs-consumer/target/pacts`) + +**The service provider part** + +The consumer contract definition (`MyConsumer-MyProvider.json`) is shared with the provider. The provider uses this contract to replay the consumer service interaction against it's service implementation. + +In this example, it happens through the pact-jvm maven plugin (See `jaxrs-provider/pom.xml`) + + +``` +[INFO] +[INFO] --- pact-jvm-provider-maven_2.11:3.2.0:verify (verify-pacts) @ example-jaxrs-cdc-provider --- + +Loading pact files for provider MyProvider from /Users/hbraun/dev/prj/wildfly-swarm-examples/jaxrs/contract-based-testing/jaxrs-provider/src/pacts +Found 1 pact files + +Verifying a pact between MyConsumer and MyProvider + [Using file /Users/hbraun/dev/prj/wildfly-swarm-examples/jaxrs/contract-based-testing/jaxrs-provider/src/pacts/MyConsumer-MyProvider.json] + Given Consumer is FOOBAR + A request to say Howdy + returns a response which + has status code 200 (OK) + has a matching body (OK) + +``` + +## Executing the tests + +To run the full cycle of tests, move to the top level directory and execute the integration tests: + +``` +cd contract-based-testing +mvn clean verify +``` + +These steps can also be executed for the consumer and provider separately: + +``` +cd [jaxrs-consumer|jaxrs-provider] +mvn clean verify +``` + +> **NOTE**: The examples do leverage the maven failsafe plugin. As such it's important execute the `verify` goal, opposed to the other lifecycles of the plugin. `verify` ensures that are relevant steps are executed to teardown the server and cleanup resource references. + + +## Further resources + +- pact-jvm: https://github.com/DiUS/pact-jvm +- consumer driven contracts : http://martinfowler.com/articles/consumerDrivenContracts.html diff --git a/jaxrs/contract-based-testing/jaxrs-consumer/pom.xml b/jaxrs/contract-based-testing/jaxrs-consumer/pom.xml new file mode 100644 index 000000000..0f48fba09 --- /dev/null +++ b/jaxrs/contract-based-testing/jaxrs-consumer/pom.xml @@ -0,0 +1,88 @@ + + + + 4.0.0 + + + org.wildfly.swarm.examples + examples-jaxrs-cdc + 1.0.0.Alpha6-SNAPSHOT + ../ + + + example-jaxrs-cdc-consumer + + WildFly Swarm Examples: JAX-RS Contracts: Consumer Example + Demonstrates how service consumers creates and verify pact files. + + war + + + + + org.apache.maven.plugins + maven-war-plugin + + false + WEB-INF/lib/wildfly-swarm-*.jar + + + + org.wildfly.swarm + wildfly-swarm-plugin + + + package + + + start + + + stop + + + + + + + + + org.wildfly.swarm.examples + examples-base + + + org.wildfly.swarm + wildfly-swarm-jaxrs + ${project.version} + + + joda-time + joda-time + 2.7 + + + au.com.dius + pact-jvm-consumer-junit_2.11 + 3.2.0 + test + + + org.apache.httpcomponents + httpclient + 4.5.1 + test + + + org.apache.httpcomponents + fluent-hc + 4.5.1 + test + + + + diff --git a/jaxrs/contract-based-testing/jaxrs-consumer/src/it/java/org/wildfly/swarm/it/jaxrs/ConsumerTest.java b/jaxrs/contract-based-testing/jaxrs-consumer/src/it/java/org/wildfly/swarm/it/jaxrs/ConsumerTest.java new file mode 100644 index 000000000..8acd025cd --- /dev/null +++ b/jaxrs/contract-based-testing/jaxrs-consumer/src/it/java/org/wildfly/swarm/it/jaxrs/ConsumerTest.java @@ -0,0 +1,54 @@ +package org.wildfly.swarm.it.jaxrs; + +import au.com.dius.pact.consumer.ConsumerPactTest; +import au.com.dius.pact.consumer.dsl.PactDslWithProvider; +import au.com.dius.pact.model.PactFragment; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/** + * Declares the expected interactions and starts a mock server. + * The actual client code is then tested in {@link #runTest(String)}. + * + * @author Heiko Braun + * @since 03/12/15 + */ +public class ConsumerTest extends ConsumerPactTest { + + @Override + protected PactFragment createFragment(PactDslWithProvider builder) { + Map requestHeader = new HashMap<>(); + requestHeader.put("client-name", "FOOBAR"); + + return builder + .given("Consumer is FOOBAR") + .uponReceiving("A request to say Howdy") + .path("/") + .method("POST") + .headers(requestHeader) + .willRespondWith() + .status(200) + .body("Howdy FOOBAR") + .toFragment(); + } + + + @Override + protected String providerName() { + return "MyProvider"; + } + + @Override + protected String consumerName() { + return "MyConsumer"; + } + + @Override + protected void runTest(String url) throws IOException { + assertEquals(new ProviderClient(url).hello("FOOBAR"), "Howdy FOOBAR"); + } +} \ No newline at end of file diff --git a/jaxrs/contract-based-testing/jaxrs-consumer/src/it/java/org/wildfly/swarm/it/jaxrs/ProviderClient.java b/jaxrs/contract-based-testing/jaxrs-consumer/src/it/java/org/wildfly/swarm/it/jaxrs/ProviderClient.java new file mode 100644 index 000000000..72ed85083 --- /dev/null +++ b/jaxrs/contract-based-testing/jaxrs-consumer/src/it/java/org/wildfly/swarm/it/jaxrs/ProviderClient.java @@ -0,0 +1,28 @@ +package org.wildfly.swarm.it.jaxrs; + +import org.apache.http.client.fluent.Request; + +import java.io.IOException; + +/** + * An example client component that invokes on a service. + * @author Heiko Braun + * @since 03/12/15 + */ +public class ProviderClient { + + private final String url; + + public ProviderClient(String url) { + this.url = url; + } + + public String hello(String name) throws IOException { + String response = Request.Post(url + "/") + .addHeader("client-name", name) + .execute() + .returnContent() + .asString(); + return response; + } +} diff --git a/jaxrs/contract-based-testing/jaxrs-consumer/src/main/java/org/wildfly/swarm/examples/jaxrs/MyApplication.java b/jaxrs/contract-based-testing/jaxrs-consumer/src/main/java/org/wildfly/swarm/examples/jaxrs/MyApplication.java new file mode 100644 index 000000000..573c80f4d --- /dev/null +++ b/jaxrs/contract-based-testing/jaxrs-consumer/src/main/java/org/wildfly/swarm/examples/jaxrs/MyApplication.java @@ -0,0 +1,14 @@ +package org.wildfly.swarm.examples.jaxrs; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +/** + * @author Bob McWhirter + */ +@ApplicationPath("/") +public class MyApplication extends Application { + + public MyApplication() { + } +} diff --git a/jaxrs/contract-based-testing/jaxrs-consumer/src/main/java/org/wildfly/swarm/examples/jaxrs/MyResource.java b/jaxrs/contract-based-testing/jaxrs-consumer/src/main/java/org/wildfly/swarm/examples/jaxrs/MyResource.java new file mode 100644 index 000000000..dc5abe7f9 --- /dev/null +++ b/jaxrs/contract-based-testing/jaxrs-consumer/src/main/java/org/wildfly/swarm/examples/jaxrs/MyResource.java @@ -0,0 +1,19 @@ +package org.wildfly.swarm.examples.jaxrs; + +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; + +/** + * @author Heiko Braun + */ +@Path("/") +public class MyResource { + + @POST + @Produces("text/plain") + public String getName(@HeaderParam("client-name") String name) { + return "Howdy " + name; + } +} diff --git a/jaxrs/contract-based-testing/jaxrs-provider/pom.xml b/jaxrs/contract-based-testing/jaxrs-provider/pom.xml new file mode 100644 index 000000000..3888b0dc6 --- /dev/null +++ b/jaxrs/contract-based-testing/jaxrs-provider/pom.xml @@ -0,0 +1,115 @@ + + + + 4.0.0 + + + org.wildfly.swarm.examples + examples-jaxrs-cdc + 1.0.0.Alpha6-SNAPSHOT + ../ + + + example-jaxrs-cdc-provider + + WildFly Swarm Examples: JAX-RS Contracts: Provider Example + Demonstrates how service providers are being tested based on pact files. + + war + + + + + org.apache.maven.plugins + maven-war-plugin + + false + WEB-INF/lib/wildfly-swarm-*.jar + + + + org.wildfly.swarm + wildfly-swarm-plugin + + + package + + + start + + + stop + + + + + + au.com.dius + pact-jvm-provider-maven_2.11 + 3.2.0 + + + + MyProvider + http + localhost + 8080 + / + src/pacts + + + + + + verify-pacts + integration-test + + verify + + + + + + + + + + org.wildfly.swarm.examples + examples-base + + + org.wildfly.swarm + wildfly-swarm-jaxrs + ${project.version} + + + joda-time + joda-time + 2.7 + + + au.com.dius + pact-jvm-provider-junit_2.11 + 3.2.0 + test + + + org.apache.httpcomponents + httpclient + 4.5.1 + test + + + org.apache.httpcomponents + fluent-hc + 4.5.1 + test + + + + diff --git a/jaxrs/contract-based-testing/jaxrs-provider/src/it/java/org/wildfly/swarm/it/jaxrs/JAXRSApplicationIT.java b/jaxrs/contract-based-testing/jaxrs-provider/src/it/java/org/wildfly/swarm/it/jaxrs/JAXRSApplicationIT.java new file mode 100644 index 000000000..be8798c72 --- /dev/null +++ b/jaxrs/contract-based-testing/jaxrs-provider/src/it/java/org/wildfly/swarm/it/jaxrs/JAXRSApplicationIT.java @@ -0,0 +1,26 @@ +package org.wildfly.swarm.it.jaxrs; + +import org.jboss.arquillian.drone.api.annotation.Drone; +import org.jboss.arquillian.junit.Arquillian; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.openqa.selenium.WebDriver; +import org.wildfly.swarm.it.AbstractIntegrationTest; + +import static org.fest.assertions.Assertions.assertThat; + +/** + * @author Bob McWhirter + */ +@RunWith(Arquillian.class) +public class JAXRSApplicationIT extends AbstractIntegrationTest { + + @Drone + WebDriver browser; + + @Test + public void testIt() { + browser.navigate().to("http://localhost:8080/"); + assertThat(browser.getPageSource()).contains("Howdy at "); + } +} diff --git a/jaxrs/contract-based-testing/jaxrs-provider/src/main/java/org/wildfly/swarm/examples/jaxrs/MyApplication.java b/jaxrs/contract-based-testing/jaxrs-provider/src/main/java/org/wildfly/swarm/examples/jaxrs/MyApplication.java new file mode 100644 index 000000000..573c80f4d --- /dev/null +++ b/jaxrs/contract-based-testing/jaxrs-provider/src/main/java/org/wildfly/swarm/examples/jaxrs/MyApplication.java @@ -0,0 +1,14 @@ +package org.wildfly.swarm.examples.jaxrs; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +/** + * @author Bob McWhirter + */ +@ApplicationPath("/") +public class MyApplication extends Application { + + public MyApplication() { + } +} diff --git a/jaxrs/contract-based-testing/jaxrs-provider/src/main/java/org/wildfly/swarm/examples/jaxrs/MyResource.java b/jaxrs/contract-based-testing/jaxrs-provider/src/main/java/org/wildfly/swarm/examples/jaxrs/MyResource.java new file mode 100644 index 000000000..e7be17200 --- /dev/null +++ b/jaxrs/contract-based-testing/jaxrs-provider/src/main/java/org/wildfly/swarm/examples/jaxrs/MyResource.java @@ -0,0 +1,26 @@ +package org.wildfly.swarm.examples.jaxrs; + +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; + +/** + * @author Heiko Braun + */ +@Path("/") +public class MyResource { + + @GET + @Produces("text/plain") + public String get() { + return "Howdy at localhost"; + } + + @POST + @Produces("text/plain") + public String getName(@HeaderParam("client-name") String name) { + return "Howdy " + name; + } +} diff --git a/jaxrs/contract-based-testing/jaxrs-provider/src/pacts/MyConsumer-MyProvider.json b/jaxrs/contract-based-testing/jaxrs-provider/src/pacts/MyConsumer-MyProvider.json new file mode 100644 index 000000000..5a67f9407 --- /dev/null +++ b/jaxrs/contract-based-testing/jaxrs-provider/src/pacts/MyConsumer-MyProvider.json @@ -0,0 +1,33 @@ +{ + "provider": { + "name": "MyProvider" + }, + "consumer": { + "name": "MyConsumer" + }, + "interactions": [ + { + "providerState": "Consumer is FOOBAR", + "description": "A request to say Howdy", + "request": { + "method": "POST", + "path": "/", + "headers": { + "client-name": "FOOBAR" + } + }, + "response": { + "status": 200, + "body": "Howdy FOOBAR" + } + } + ], + "metadata": { + "pact-specification": { + "version": "2.0.0" + }, + "pact-jvm": { + "version": "3.2.0" + } + } +} \ No newline at end of file diff --git a/jaxrs/contract-based-testing/pom.xml b/jaxrs/contract-based-testing/pom.xml new file mode 100644 index 000000000..dc506dd6a --- /dev/null +++ b/jaxrs/contract-based-testing/pom.xml @@ -0,0 +1,30 @@ + + + + 4.0.0 + + + org.wildfly.swarm.examples + wildfly-swarm-examples-parent + 1.0.0.Alpha6-SNAPSHOT + ../ + + + examples-jaxrs-cdc + + WildFly Swarm Examples: Consumer Driven Contracts + Demonstrates a setup for contract based testing + + pom + + + + jaxrs-consumer + jaxrs-provider + + diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 18866493d..74edeabb2 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -27,5 +27,6 @@ jaxrs-war jaxrs-shrinkwrap jaxrs-cdi + contract-based-testing