From 3702d2ccc85cc89b02eca2ac904c7bcf981f9cd0 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 26 Feb 2021 13:14:03 +1100 Subject: [PATCH 01/29] chore: step 5 --- README.md | 114 ++++++++++++++++++ .../clients/ProductServiceClient.java | 2 +- .../clients/ProductServiceClientPactTest.java | 2 +- .../clients/ProductServiceClientTest.java | 2 +- 4 files changed, 117 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e4ae4d5..a07640c 100644 --- a/README.md +++ b/README.md @@ -520,3 +520,117 @@ The test has failed, as the expected path `/products/{id}` is returning 404. We The correct endpoint which the consumer should call is `/product/{id}`. Move on to [step 5](https://github.com/pact-foundation/pact-workshop-Maven-Springboot-JUnit5/tree/step5#step-5---back-to-the-client-we-go) + +## Step 5 - Back to the client we go + +We now need to update the consumer client and tests to hit the correct product path. + +First, we need to update the GET route for the client: + +In `consumer/src/main/java/io/pact/workshop/product_catalogue/clients/ProductServiceClient.java`: + +```java + public Product getProductById(long id) { + return restTemplate.getForObject(baseUrl + "/product/" + id, Product.class); + } +``` + +Then we need to update the Pact test `ID 10 exists` to use the correct endpoint in `path`. + +In `consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientPactTest.java`: + +```javascript + @Pact(consumer = "ProductCatalogue") + public RequestResponsePact singleProduct(PactDslWithProvider builder) { + return builder + .given("product with ID 10 exists", "id", 10) + .uponReceiving("get product with ID 10") + .path("/product/10") + .willRespondWith() + .status(200) + .body( + new PactDslJsonBody() + .integerType("id", 10L) + .stringType("name", "28 Degrees") + .stringType("type", "CREDIT_CARD") + .stringType("code", "CC_001") + .stringType("version", "v1") + ) + .toPact(); + } +``` + +![Pact Verification](diagrams/workshop_step5_pact.svg) + +Let's run and generate an updated pact file on the client: + +```console +❯ ./mvnw verify + +<<< Omitted >>> + +[INFO] +[INFO] Results: +[INFO] +[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0 +[INFO] +[INFO] +[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ product-catalogue --- +[INFO] Building jar: /home/ronald/Development/Projects/Pact/pact-workshop-Maven-Springboot-JUnit5/consumer/target/product-catalogue-0.0.1-SNAPSHOT.jar +[INFO] +[INFO] --- spring-boot-maven-plugin:2.4.3:repackage (repackage) @ product-catalogue --- +[INFO] Replacing main artifact with repackaged archive +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +``` + +Now we run the provider tests again with the updated contract + +Copy the updated contract located in `consumer/target/pacts/ProductCatalogue-ProductService.json` to `provider/pacts`. + +Run the command: + +```console +❯ ./mvnw verify + +<<< Omitted >>> + +Verifying a pact between ProductCatalogue and ProductService + [Using File pacts/ProductCatalogue-ProductService.json] + Given product with ID 10 exists + get product with ID 10 +2021-02-26 13:11:45.229 INFO 96199 --- [o-auto-1-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' +2021-02-26 13:11:45.229 INFO 96199 --- [o-auto-1-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' +2021-02-26 13:11:45.230 INFO 96199 --- [o-auto-1-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms + returns a response which + has status code 200 (OK) + has a matching body (OK) +2021-02-26 13:11:45.356 WARN 96199 --- [ main] a.c.d.p.p.DefaultTestResultAccumulator : Not all of the 2 were verified. The following were missing: +2021-02-26 13:11:45.356 WARN 96199 --- [ main] a.c.d.p.p.DefaultTestResultAccumulator : get all products +2021-02-26 13:11:45.366 INFO 96199 --- [ main] p.j.PactVerificationStateChangeExtension : Invoking state change method 'products exists':SETUP + +Verifying a pact between ProductCatalogue and ProductService + [Using File pacts/ProductCatalogue-ProductService.json] + Given products exists + get all products + returns a response which + has status code 200 (OK) + has a matching body (OK) +2021-02-26 13:11:45.485 WARN 96199 --- [ main] a.c.d.p.p.DefaultTestResultAccumulator : Skipping publishing of verification results as it has been disabled (pact.verifier.publishResults is not 'true') +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.573 s - in io.pact.workshop.product_service.PactVerificationTest +2021-02-26 13:11:45.527 INFO 96199 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor' +2021-02-26 13:11:45.527 INFO 96199 --- [extShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' +2021-02-26 13:11:45.528 INFO 96199 --- [extShutdownHook] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down' +2021-02-26 13:11:45.532 INFO 96199 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... +2021-02-26 13:11:45.534 INFO 96199 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. +[INFO] +[INFO] Results: +[INFO] +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 +[INFO] +``` + +Yay - green ✅! + +Move on to [step 6](https://github.com/pact-foundation/pact-workshop-Maven-Springboot-JUnit5/tree/step6#step-6---consumer-updates-contract-for-missing-products) diff --git a/consumer/src/main/java/io/pact/workshop/product_catalogue/clients/ProductServiceClient.java b/consumer/src/main/java/io/pact/workshop/product_catalogue/clients/ProductServiceClient.java index 9f315fb..a8001fd 100644 --- a/consumer/src/main/java/io/pact/workshop/product_catalogue/clients/ProductServiceClient.java +++ b/consumer/src/main/java/io/pact/workshop/product_catalogue/clients/ProductServiceClient.java @@ -19,7 +19,7 @@ public ProductServiceResponse fetchProducts() { } public Product getProductById(long id) { - return restTemplate.getForObject(baseUrl + "/products/" + id, Product.class); + return restTemplate.getForObject(baseUrl + "/product/" + id, Product.class); } public String getBaseUrl() { diff --git a/consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientPactTest.java b/consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientPactTest.java index a5143c5..e0f421c 100644 --- a/consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientPactTest.java +++ b/consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientPactTest.java @@ -53,7 +53,7 @@ public RequestResponsePact singleProduct(PactDslWithProvider builder) { return builder .given("product with ID 10 exists", "id", 10) .uponReceiving("get product with ID 10") - .path("/products/10") + .path("/product/10") .willRespondWith() .status(200) .body( diff --git a/consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientTest.java b/consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientTest.java index 30dfc4a..8a820c2 100644 --- a/consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientTest.java +++ b/consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientTest.java @@ -65,7 +65,7 @@ void fetchProducts(@Wiremock WireMockServer server, @WiremockUri String uri) { void getProductById(@Wiremock WireMockServer server, @WiremockUri String uri) { productServiceClient.setBaseUrl(uri); server.stubFor( - get(urlPathEqualTo("/products/10")) + get(urlPathEqualTo("/product/10")) .willReturn(aResponse() .withStatus(200) .withBody("{\n" + From f04e60be405da98ca60e043af69f0a8bdc8e3425 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 26 Feb 2021 13:16:46 +1100 Subject: [PATCH 02/29] chore: update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a07640c..2281dc7 100644 --- a/README.md +++ b/README.md @@ -562,7 +562,7 @@ In `consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductSer ![Pact Verification](diagrams/workshop_step5_pact.svg) -Let's run and generate an updated pact file on the client: +Let's run and generate an updated pact file on the consumer: ```console ❯ ./mvnw verify From 96535c349f918626527f559ec3767a0913919e25 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 26 Feb 2021 13:48:04 +1100 Subject: [PATCH 03/29] chore: step 6 --- README.md | 170 ++++++++++++++++++ .../clients/ProductServiceClientPactTest.java | 67 ++++++- provider/src/main/resources/data.sql | 6 +- .../product_service/PactVerificationTest.java | 2 + 4 files changed, 233 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 2281dc7..824beb4 100644 --- a/README.md +++ b/README.md @@ -634,3 +634,173 @@ Verifying a pact between ProductCatalogue and ProductService Yay - green ✅! Move on to [step 6](https://github.com/pact-foundation/pact-workshop-Maven-Springboot-JUnit5/tree/step6#step-6---consumer-updates-contract-for-missing-products) + +## Step 6 - Consumer updates contract for missing products + +We're now going to add 2 more scenarios for the contract + +- What happens when we make a call for a product that doesn't exist? We assume we'll get a `404`. + +- What happens when we make a call for getting all products but none exist at the moment? We assume a `200` with an empty array. + +Let's write a test for these scenarios, and then generate an updated pact file. + +In `consumer/src/api.pact.spec.js`: + +```java + @Pact(consumer = "ProductCatalogue") + public RequestResponsePact noProducts(PactDslWithProvider builder) { + return builder + .given("no products exists") + .uponReceiving("get all products") + .path("/products") + .willRespondWith() + .status(200) + .body( + new PactDslJsonBody().array("products") + ) + .toPact(); + } + + @Test + @PactTestFor(pactMethod = "noProducts") + void testNoProducts(MockServer mockServer) { + productServiceClient.setBaseUrl(mockServer.getUrl()); + ProductServiceResponse products = productServiceClient.fetchProducts(); + assertThat(products.getProducts(), hasSize(0)); + } + + @Pact(consumer = "ProductCatalogue") + public RequestResponsePact singleProductNotExists(PactDslWithProvider builder) { + return builder + .given("product with ID 10 does not exist", "id", 10) + .uponReceiving("get product with ID 10") + .path("/product/10") + .willRespondWith() + .status(404) + .toPact(); + } + + @Test + @PactTestFor(pactMethod = "singleProductNotExists") + void testSingleProductNotExists(MockServer mockServer) { + productServiceClient.setBaseUrl(mockServer.getUrl()); + try { + productServiceClient.getProductById(10L); + fail("Expected service call to throw an exception"); + } catch (HttpClientErrorException ex) { + assertThat(ex.getMessage(), containsString("404 Not Found")); + } + } +``` + +Notice that our new tests look almost identical to our previous tests, and only differ on the expectations of the +_response_ - the HTTP request expectations are exactly the same. + +```console +❯ ./mvnw verify + +<<< Omitted >>> + +[INFO] +[INFO] Results: +[INFO] +[INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0 +[INFO] +[INFO] +[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ product-catalogue --- +[INFO] Building jar: /home/ronald/Development/Projects/Pact/pact-workshop-Maven-Springboot-JUnit5/consumer/target/product-catalogue-0.0.1-SNAPSHOT.jar +[INFO] +[INFO] --- spring-boot-maven-plugin:2.4.3:repackage (repackage) @ product-catalogue --- +[INFO] Replacing main artifact with repackaged archive +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +``` + +What does our provider have to say about this new test. Again, copy the updated pact file into the provider's pact directory and run the command: + +```console +❯ ./mvnw verify + +<<< Omitted >>> + +Verifying a pact between ProductCatalogue and ProductService + [Using File pacts/ProductCatalogue-ProductService.json] + Given no products exists + get all products +2021-02-26 13:45:27.930 INFO 100121 --- [o-auto-1-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' +2021-02-26 13:45:27.932 INFO 100121 --- [o-auto-1-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' +2021-02-26 13:45:27.934 INFO 100121 --- [o-auto-1-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms + returns a response which + has status code 200 (OK) + has a matching body (FAILED) + +Failures: + +1) Verifying a pact between ProductCatalogue and ProductService - get all products has a matching body + + 1.1) body: $.products Expected an empty List but received [{"code":"CC_01_VISA","id":9,"name":"Gem Visa","type":"CREDIT_CARD","version":"v1"},{"code":"CC_02_OTH","id":10,"name":"28 Degrees","type":"CREDIT_CARD","version":"v1"},{"code":"LN_PERS_01","id":11,"name":"MyFlexiPay","type":"PERSONAL_LOAN","version":"v2"}] + + [ + - + + { + + "id": 9, + + "name": "Gem Visa", + + "type": "CREDIT_CARD", + + "version": "v1", + + "code": "CC_01_VISA" + + }, + + { + + "id": 10, + + "name": "28 Degrees", + + "type": "CREDIT_CARD", + + "version": "v1", + + "code": "CC_02_OTH" + + }, + + { + + "id": 11, + + "name": "MyFlexiPay", + + "type": "PERSONAL_LOAN", + + "version": "v2", + + "code": "LN_PERS_01" + + } + ] + + + +2021-02-26 13:45:28.460 WARN 100121 --- [ main] a.c.d.p.p.DefaultTestResultAccumulator : Not all of the 4 were verified. The following were missing: +2021-02-26 13:45:28.460 WARN 100121 --- [ main] a.c.d.p.p.DefaultTestResultAccumulator : get product with ID 10 +2021-02-26 13:45:28.461 WARN 100121 --- [ main] a.c.d.p.p.DefaultTestResultAccumulator : get product with ID 10 +2021-02-26 13:45:28.461 WARN 100121 --- [ main] a.c.d.p.p.DefaultTestResultAccumulator : get all products +2021-02-26 13:45:28.463 WARN 100121 --- [ main] p.j.PactVerificationStateChangeExtension : Did not find a test class method annotated with @State("no products exists") +for Interaction "get all products" +with Consumer "ProductCatalogue" +2021-02-26 13:45:28.530 WARN 100121 --- [ main] p.j.PactVerificationStateChangeExtension : Did not find a test class method annotated with @State("product with ID 10 does not exist") +for Interaction "get product with ID 10" +with Consumer "ProductCatalogue" + +Verifying a pact between ProductCatalogue and ProductService + [Using File pacts/ProductCatalogue-ProductService.json] + Given product with ID 10 does not exist + get product with ID 10 + returns a response which + has status code 404 (FAILED) + has a matching body (OK) + +Failures: + +1) Verifying a pact between ProductCatalogue and ProductService - get product with ID 10: has status code 404 + + 1.1) status: expected status of 404 but was 200 + +``` + +We expected this failure, because the product we are requesting does in fact exist! What we want to test for, +is what happens if there is a different *state* on the Provider. This is what is referred to as "Provider states", +and how Pact gets around test ordering and related issues. + +We could resolve this by updating our consumer test to use a known non-existent product, but it's worth understanding +how Provider states work more generally. + +*Move on to [step 7](https://github.com/pact-foundation/pact-workshop-Maven-Springboot-JUnit5/tree/step7#step-7---adding-the-missing-states)* diff --git a/consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientPactTest.java b/consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientPactTest.java index e0f421c..33e6bf4 100644 --- a/consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientPactTest.java +++ b/consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientPactTest.java @@ -12,14 +12,17 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.web.client.HttpClientErrorException; import java.io.IOException; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.fail; @SpringBootTest @ExtendWith(PactConsumerTestExt.class) @@ -48,6 +51,15 @@ public RequestResponsePact allProducts(PactDslWithProvider builder) { .toPact(); } + @Test + @PactTestFor(pactMethod = "allProducts") + void testAllProducts(MockServer mockServer) { + productServiceClient.setBaseUrl(mockServer.getUrl()); + List products = productServiceClient.fetchProducts().getProducts(); + assertThat(products, hasSize(2)); + assertThat(products.get(0), is(equalTo(new Product(9L, "Gem Visa", "CREDIT_CARD", null, null)))); + } + @Pact(consumer = "ProductCatalogue") public RequestResponsePact singleProduct(PactDslWithProvider builder) { return builder @@ -68,18 +80,55 @@ public RequestResponsePact singleProduct(PactDslWithProvider builder) { } @Test - @PactTestFor(pactMethod = "allProducts", port="9999") - void testAllProducts(MockServer mockServer) throws IOException { + @PactTestFor(pactMethod = "singleProduct") + void testSingleProduct(MockServer mockServer) { productServiceClient.setBaseUrl(mockServer.getUrl()); - List products = productServiceClient.fetchProducts().getProducts(); - assertThat(products, hasSize(2)); - assertThat(products.get(0), is(equalTo(new Product(9L, "Gem Visa", "CREDIT_CARD", null, null)))); + Product product = productServiceClient.getProductById(10L); + assertThat(product, is(equalTo(new Product(10L, "28 Degrees", "CREDIT_CARD", "v1", "CC_001")))); + } + + @Pact(consumer = "ProductCatalogue") + public RequestResponsePact noProducts(PactDslWithProvider builder) { + return builder + .given("no products exists") + .uponReceiving("get all products") + .path("/products") + .willRespondWith() + .status(200) + .body( + new PactDslJsonBody().array("products") + ) + .toPact(); } @Test - @PactTestFor(pactMethod = "singleProduct", port="9999") - void testSingleProduct(MockServer mockServer) throws IOException { - Product product = productServiceClient.getProductById(10L); - assertThat(product, is(equalTo(new Product(10L, "28 Degrees", "CREDIT_CARD", "v1", "CC_001")))); + @PactTestFor(pactMethod = "noProducts") + void testNoProducts(MockServer mockServer) { + productServiceClient.setBaseUrl(mockServer.getUrl()); + ProductServiceResponse products = productServiceClient.fetchProducts(); + assertThat(products.getProducts(), hasSize(0)); + } + + @Pact(consumer = "ProductCatalogue") + public RequestResponsePact singleProductNotExists(PactDslWithProvider builder) { + return builder + .given("product with ID 10 does not exist", "id", 10) + .uponReceiving("get product with ID 10") + .path("/product/10") + .willRespondWith() + .status(404) + .toPact(); + } + + @Test + @PactTestFor(pactMethod = "singleProductNotExists") + void testSingleProductNotExists(MockServer mockServer) { + productServiceClient.setBaseUrl(mockServer.getUrl()); + try { + productServiceClient.getProductById(10L); + fail("Expected service call to throw an exception"); + } catch (HttpClientErrorException ex) { + assertThat(ex.getMessage(), containsString("404 Not Found")); + } } } diff --git a/provider/src/main/resources/data.sql b/provider/src/main/resources/data.sql index b795701..eaf2ede 100644 --- a/provider/src/main/resources/data.sql +++ b/provider/src/main/resources/data.sql @@ -1,3 +1,3 @@ -insert into product (id, name, type, version, code) values (1, 'Gem Visa', 'CREDIT_CARD', 'v1', 'CC_01_VISA'); -insert into product (id, name, type, version, code) values (2, '28 Degrees', 'CREDIT_CARD', 'v1', 'CC_02_OTH'); -insert into product (id, name, type, version, code) values (3, 'MyFlexiPay', 'PERSONAL_LOAN', 'v2', 'LN_PERS_01'); +insert into product (id, name, type, version, code) values (9, 'Gem Visa', 'CREDIT_CARD', 'v1', 'CC_01_VISA'); +insert into product (id, name, type, version, code) values (10, '28 Degrees', 'CREDIT_CARD', 'v1', 'CC_02_OTH'); +insert into product (id, name, type, version, code) values (11, 'MyFlexiPay', 'PERSONAL_LOAN', 'v2', 'LN_PERS_01'); diff --git a/provider/src/test/java/io/pact/workshop/product_service/PactVerificationTest.java b/provider/src/test/java/io/pact/workshop/product_service/PactVerificationTest.java index bec79ca..9e20c79 100644 --- a/provider/src/test/java/io/pact/workshop/product_service/PactVerificationTest.java +++ b/provider/src/test/java/io/pact/workshop/product_service/PactVerificationTest.java @@ -3,6 +3,7 @@ import au.com.dius.pact.provider.junit5.HttpTestTarget; import au.com.dius.pact.provider.junit5.PactVerificationContext; import au.com.dius.pact.provider.junit5.PactVerificationInvocationContextProvider; +import au.com.dius.pact.provider.junitsupport.IgnoreMissingStateChange; import au.com.dius.pact.provider.junitsupport.Provider; import au.com.dius.pact.provider.junitsupport.State; import au.com.dius.pact.provider.junitsupport.StateChangeAction; @@ -23,6 +24,7 @@ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @Provider("ProductService") @PactFolder("pacts") +@IgnoreMissingStateChange public class PactVerificationTest { @LocalServerPort private int port; From 2f1c9bdfca1a46e3dd6851c9b81ef4d4ac83eea3 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 26 Feb 2021 14:01:56 +1100 Subject: [PATCH 04/29] chore: correct seed data --- README.md | 2 +- provider/src/main/resources/data.sql | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index bcb8c5c..c7b37cd 100644 --- a/README.md +++ b/README.md @@ -528,7 +528,7 @@ Then we need to update the Pact test `ID 10 exists` to use the correct endpoint In `consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientPactTest.java`: -```javascript +```java @Pact(consumer = "ProductCatalogue") public RequestResponsePact singleProduct(PactDslWithProvider builder) { return builder diff --git a/provider/src/main/resources/data.sql b/provider/src/main/resources/data.sql index b795701..eaf2ede 100644 --- a/provider/src/main/resources/data.sql +++ b/provider/src/main/resources/data.sql @@ -1,3 +1,3 @@ -insert into product (id, name, type, version, code) values (1, 'Gem Visa', 'CREDIT_CARD', 'v1', 'CC_01_VISA'); -insert into product (id, name, type, version, code) values (2, '28 Degrees', 'CREDIT_CARD', 'v1', 'CC_02_OTH'); -insert into product (id, name, type, version, code) values (3, 'MyFlexiPay', 'PERSONAL_LOAN', 'v2', 'LN_PERS_01'); +insert into product (id, name, type, version, code) values (9, 'Gem Visa', 'CREDIT_CARD', 'v1', 'CC_01_VISA'); +insert into product (id, name, type, version, code) values (10, '28 Degrees', 'CREDIT_CARD', 'v1', 'CC_02_OTH'); +insert into product (id, name, type, version, code) values (11, 'MyFlexiPay', 'PERSONAL_LOAN', 'v2', 'LN_PERS_01'); From e9431e2c23c1dbe7cd74c18c8e68319df069742a Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 26 Feb 2021 14:07:10 +1100 Subject: [PATCH 05/29] fix: readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0f36b6d..3f01b9b 100644 --- a/README.md +++ b/README.md @@ -634,7 +634,7 @@ We're now going to add 2 more scenarios for the contract Let's write a test for these scenarios, and then generate an updated pact file. -In `consumer/src/api.pact.spec.js`: +In `consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientPactTest.java`: ```java @Pact(consumer = "ProductCatalogue") From d9f4f55f8f9184f003fff6b1343cece1fc883464 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 26 Feb 2021 14:33:43 +1100 Subject: [PATCH 06/29] chore: step 7 --- README.md | 85 +++++++++++++++++++ .../controllers/ProductsController.java | 10 ++- .../product_service/PactVerificationTest.java | 43 +++++++++- 3 files changed, 133 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3f01b9b..62bf5f7 100644 --- a/README.md +++ b/README.md @@ -793,3 +793,88 @@ We could resolve this by updating our consumer test to use a known non-existent how Provider states work more generally. *Move on to [step 7](https://github.com/pact-foundation/pact-workshop-Maven-Springboot-JUnit5/tree/step7#step-7---adding-the-missing-states)* + +## Step 7 - Adding the missing states + +We need to update our provider code to deal with missing products and send a `404` response. However, our test data +fixture also has product ID 10 and 11 in our database. + +In this step, we will add some state handlers to our provider Pact verification test, which will update the state +of our data store depending on which states the consumers require. + +States are invoked prior to the actual test function is invoked. For each interaction in a pact file, the order of execution is as follows: + +``` +BeforeEach -> StateHandler (setup) -> RequestFilter -> Execute Provider Test -> StateHandler (teardown) -> AfterEach +``` + +We're going to add handlers for all our states: + +- products exist +- no products exist +- product with ID 10 exists +- product with ID 10 does not exist + +Let's open up our provider Pact verification test in `provider/src/test/java/io/pact/workshop/product_service/PactVerificationTest.java`: + +```java + @State(value = "products exists", action = StateChangeAction.SETUP) + void productsExists() { + productRepository.deleteAll(); + productRepository.saveAll(Arrays.asList( + new Product(100L, "Test Product 1", "CREDIT_CARD", "v1", "CC_001"), + new Product(200L, "Test Product 2", "CREDIT_CARD", "v1", "CC_002"), + new Product(300L, "Test Product 3", "PERSONAL_LOAN", "v1", "PL_001"), + new Product(400L, "Test Product 4", "SAVINGS", "v1", "SA_001") + )); + } + + @State(value = "no products exists", action = StateChangeAction.SETUP) + void noProductsExist() { + productRepository.deleteAll(); + } + + @State(value = "product with ID 10 exists", action = StateChangeAction.SETUP) + void productExists(Map params) { + long productId = ((Number) params.get("id")).longValue(); + Optional product = productRepository.findById(productId); + if (!product.isPresent()) { + productRepository.save(new Product(productId, "Product", "TYPE", "v1", "001")); + } + } + + @State(value = "product with ID 10 does not exist", action = StateChangeAction.SETUP) + void productNotExist(Map params) { + long productId = ((Number) params.get("id")).longValue(); + Optional product = productRepository.findById(productId); + if (product.isPresent()) { + productRepository.deleteById(productId); + } + } +``` + +Let's see how we go now: + +```console +❯ ./mvnw verify + +<<< Omitted >>> + +[INFO] +[INFO] Results: +[INFO] +[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0 +[INFO] +[INFO] +[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ product-service --- +[INFO] Building jar: /home/ronald/Development/Projects/Pact/pact-workshop-Maven-Springboot-JUnit5/provider/target/product-service-1.0-SNAPSHOT.jar +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +``` + +_NOTE_: The states are not necessarily a 1 to 1 mapping with the consumer contract tests. You can reuse states amongst +different tests. In this scenario we could have used `no products exist` for both tests which would have +equally been valid. + +*Move on to [step 8](https://github.com/pact-foundation/pact-workshop-Maven-Springboot-JUnit5/tree/step8#step-8---authorization)* diff --git a/provider/src/main/java/io/pact/workshop/product_service/controllers/ProductsController.java b/provider/src/main/java/io/pact/workshop/product_service/controllers/ProductsController.java index 80b72a5..68e068d 100644 --- a/provider/src/main/java/io/pact/workshop/product_service/controllers/ProductsController.java +++ b/provider/src/main/java/io/pact/workshop/product_service/controllers/ProductsController.java @@ -3,15 +3,19 @@ import io.pact.workshop.product_service.products.Product; import io.pact.workshop.product_service.products.ProductRepository; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import java.util.List; -import java.util.Optional; @RestController public class ProductsController { + @ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "product not found") + public static class ProductNotFoundException extends RuntimeException { } + @Autowired private ProductRepository productRepository; @@ -21,7 +25,7 @@ public ProductsResponse allProducts() { } @GetMapping("/product/{id}") - public Optional productById(@PathVariable("id") Long id) { - return productRepository.findById(id); + public Product productById(@PathVariable("id") Long id) { + return productRepository.findById(id).orElseThrow(ProductNotFoundException::new); } } diff --git a/provider/src/test/java/io/pact/workshop/product_service/PactVerificationTest.java b/provider/src/test/java/io/pact/workshop/product_service/PactVerificationTest.java index 99654ef..9775632 100644 --- a/provider/src/test/java/io/pact/workshop/product_service/PactVerificationTest.java +++ b/provider/src/test/java/io/pact/workshop/product_service/PactVerificationTest.java @@ -3,9 +3,11 @@ import au.com.dius.pact.provider.junit5.HttpTestTarget; import au.com.dius.pact.provider.junit5.PactVerificationContext; import au.com.dius.pact.provider.junit5.PactVerificationInvocationContextProvider; -import au.com.dius.pact.provider.junitsupport.IgnoreMissingStateChange; import au.com.dius.pact.provider.junitsupport.Provider; +import au.com.dius.pact.provider.junitsupport.State; +import au.com.dius.pact.provider.junitsupport.StateChangeAction; import au.com.dius.pact.provider.junitsupport.loader.PactFolder; +import io.pact.workshop.product_service.products.Product; import io.pact.workshop.product_service.products.ProductRepository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.TestTemplate; @@ -14,10 +16,13 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; +import java.util.Arrays; +import java.util.Map; +import java.util.Optional; + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @Provider("ProductService") @PactFolder("pacts") -@IgnoreMissingStateChange public class PactVerificationTest { @LocalServerPort private int port; @@ -35,4 +40,38 @@ void setup(PactVerificationContext context) { void pactVerificationTestTemplate(PactVerificationContext context) { context.verifyInteraction(); } + + @State(value = "products exists", action = StateChangeAction.SETUP) + void productsExists() { + productRepository.deleteAll(); + productRepository.saveAll(Arrays.asList( + new Product(100L, "Test Product 1", "CREDIT_CARD", "v1", "CC_001"), + new Product(200L, "Test Product 2", "CREDIT_CARD", "v1", "CC_002"), + new Product(300L, "Test Product 3", "PERSONAL_LOAN", "v1", "PL_001"), + new Product(400L, "Test Product 4", "SAVINGS", "v1", "SA_001") + )); + } + + @State(value = "no products exists", action = StateChangeAction.SETUP) + void noProductsExist() { + productRepository.deleteAll(); + } + + @State(value = "product with ID 10 exists", action = StateChangeAction.SETUP) + void productExists(Map params) { + long productId = ((Number) params.get("id")).longValue(); + Optional product = productRepository.findById(productId); + if (!product.isPresent()) { + productRepository.save(new Product(productId, "Product", "TYPE", "v1", "001")); + } + } + + @State(value = "product with ID 10 does not exist", action = StateChangeAction.SETUP) + void productNotExist(Map params) { + long productId = ((Number) params.get("id")).longValue(); + Optional product = productRepository.findById(productId); + if (product.isPresent()) { + productRepository.deleteById(productId); + } + } } From 5cb0caa3582e656622429d86b7a3e36d922060b7 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 15:51:27 +1100 Subject: [PATCH 07/29] chore: update readme --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c7b37cd..a8b7f64 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ If running this as a team workshop format, you may want to take a look through t - JDK 8 or above - Maven 3 +- Docker for step 11 ## Scenario @@ -76,8 +77,14 @@ public class ProductServiceClient { } ``` -After forking or cloning the repository, we need to build the app and install the dependencies with `./mvnw verify`. -We can run the app with `java -jar target/product-catalogue-0.0.1-SNAPSHOT.jar`. +After forking or cloning the repository, we need to build the app and install the dependencies. Run the following +in the `consumer` sub-directory: + +```console +/consumer ❯ ./mvnw verify +``` + +We can run the app with `/consumer ❯ java -jar target/product-catalogue-0.0.1-SNAPSHOT.jar`. Accessing the URL for the app in the browser gives us a 500 error page as the downstream service is not running. You will also see an exception in the Springboot console output. From d467aa860b2e6eef0625e65ad6c0237c2346b2f5 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 15:52:39 +1100 Subject: [PATCH 08/29] chore: update readme --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a8b7f64..5bfb70e 100644 --- a/README.md +++ b/README.md @@ -81,10 +81,14 @@ After forking or cloning the repository, we need to build the app and install th in the `consumer` sub-directory: ```console -/consumer ❯ ./mvnw verify +consumer ❯ ./mvnw verify ``` -We can run the app with `/consumer ❯ java -jar target/product-catalogue-0.0.1-SNAPSHOT.jar`. +We can run the app with + +```console +consumer ❯ java -jar target/product-catalogue-0.0.1-SNAPSHOT.jar +``` Accessing the URL for the app in the browser gives us a 500 error page as the downstream service is not running. You will also see an exception in the Springboot console output. From ed442e160b77059bdc390e13f1de8dd1e6a07df9 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 16:00:40 +1100 Subject: [PATCH 09/29] chore: update readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5bfb70e..e94f8ba 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ You can see the client interface test we created in `consumer/src/test/java/io/p Let's run this test and see it all pass: ```console -❯ ./mvnw verify +consumer ❯ ./mvnw verify [INFO] Scanning for projects... [INFO] [INFO] -----------------< io.pact.workshop:product-catalogue >----------------- @@ -200,7 +200,7 @@ Meanwhile, our provider team has started building out their API in parallel. Let ```console # Terminal 1 -❯ mvn spring-boot:run +consumer ❯ mvn spring-boot:run <<< Omitted >>> @@ -227,7 +227,7 @@ Meanwhile, our provider team has started building out their API in parallel. Let ```console # Terminal 2 -> mvn spring-boot:run +provider ❯ mvn spring-boot:run <<< Omitted >>> From e3425abf653c08b7bac0b0ac863844fe4cc12733 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 16:14:30 +1100 Subject: [PATCH 10/29] chore: update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e94f8ba..0d7d768 100644 --- a/README.md +++ b/README.md @@ -383,7 +383,7 @@ Running this test also passes, but it creates a pact file which we can use to va provider side, and have conversation around. ```console -❯ ./mvnw verify +consumer ❯ ./mvnw verify [INFO] Scanning for projects... [INFO] [INFO] -----------------< io.pact.workshop:product-catalogue >----------------- From 832e52ae84f191a191996a7b1c788d5735094efa Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 16:22:28 +1100 Subject: [PATCH 11/29] chore: update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d7d768..ecf0a92 100644 --- a/README.md +++ b/README.md @@ -486,7 +486,7 @@ provider is and where the pact files are. We also set the test target to point t We now need to validate the pact generated by the consumer is valid by running the test, which should fail: ```console -❯ ./mvnw verify +provider ❯ ./mvnw verify <<< Omitted >>> From 24a50c0d49152ef74200b46f9d095845ee3911ac Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 16:25:06 +1100 Subject: [PATCH 12/29] chore: update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ecf0a92..4ba860b 100644 --- a/README.md +++ b/README.md @@ -565,7 +565,7 @@ In `consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductSer Let's run and generate an updated pact file on the consumer: ```console -❯ ./mvnw verify +consumer ❯ ./mvnw verify <<< Omitted >>> @@ -592,7 +592,7 @@ Copy the updated contract located in `consumer/target/pacts/ProductCatalogue-Pro Run the command: ```console -❯ ./mvnw verify +provider ❯ ./mvnw verify <<< Omitted >>> From 6fce343c4b8c66931cf1acf428602949152de992 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 15:51:27 +1100 Subject: [PATCH 13/29] chore: update readme --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3f01b9b..fbb22d5 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ If running this as a team workshop format, you may want to take a look through t - JDK 8 or above - Maven 3 +- Docker for step 11 ## Scenario @@ -76,8 +77,14 @@ public class ProductServiceClient { } ``` -After forking or cloning the repository, we need to build the app and install the dependencies with `./mvnw verify`. -We can run the app with `java -jar target/product-catalogue-0.0.1-SNAPSHOT.jar`. +After forking or cloning the repository, we need to build the app and install the dependencies. Run the following +in the `consumer` sub-directory: + +```console +/consumer ❯ ./mvnw verify +``` + +We can run the app with `/consumer ❯ java -jar target/product-catalogue-0.0.1-SNAPSHOT.jar`. Accessing the URL for the app in the browser gives us a 500 error page as the downstream service is not running. You will also see an exception in the Springboot console output. From 5707d516d058ce29417d6adfa3e9df5ca2bcdafc Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 15:52:39 +1100 Subject: [PATCH 14/29] chore: update readme --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fbb22d5..ccaf80f 100644 --- a/README.md +++ b/README.md @@ -81,10 +81,14 @@ After forking or cloning the repository, we need to build the app and install th in the `consumer` sub-directory: ```console -/consumer ❯ ./mvnw verify +consumer ❯ ./mvnw verify ``` -We can run the app with `/consumer ❯ java -jar target/product-catalogue-0.0.1-SNAPSHOT.jar`. +We can run the app with + +```console +consumer ❯ java -jar target/product-catalogue-0.0.1-SNAPSHOT.jar +``` Accessing the URL for the app in the browser gives us a 500 error page as the downstream service is not running. You will also see an exception in the Springboot console output. From 863e84a23b2e5b44510b7da9075c3bbb95e6dd44 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 16:00:40 +1100 Subject: [PATCH 15/29] chore: update readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ccaf80f..45d1556 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ You can see the client interface test we created in `consumer/src/test/java/io/p Let's run this test and see it all pass: ```console -❯ ./mvnw verify +consumer ❯ ./mvnw verify [INFO] Scanning for projects... [INFO] [INFO] -----------------< io.pact.workshop:product-catalogue >----------------- @@ -200,7 +200,7 @@ Meanwhile, our provider team has started building out their API in parallel. Let ```console # Terminal 1 -❯ mvn spring-boot:run +consumer ❯ mvn spring-boot:run <<< Omitted >>> @@ -227,7 +227,7 @@ Meanwhile, our provider team has started building out their API in parallel. Let ```console # Terminal 2 -> mvn spring-boot:run +provider ❯ mvn spring-boot:run <<< Omitted >>> From a118c87a655e5189b29459c2f3534fe5348a793d Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 16:14:30 +1100 Subject: [PATCH 16/29] chore: update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 45d1556..e0c74a9 100644 --- a/README.md +++ b/README.md @@ -383,7 +383,7 @@ Running this test also passes, but it creates a pact file which we can use to va provider side, and have conversation around. ```console -❯ ./mvnw verify +consumer ❯ ./mvnw verify [INFO] Scanning for projects... [INFO] [INFO] -----------------< io.pact.workshop:product-catalogue >----------------- From 2ed798113f2da121fa2b26c97af30d4226a1c59c Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 16:22:28 +1100 Subject: [PATCH 17/29] chore: update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e0c74a9..8331bf2 100644 --- a/README.md +++ b/README.md @@ -486,7 +486,7 @@ provider is and where the pact files are. We also set the test target to point t We now need to validate the pact generated by the consumer is valid by running the test, which should fail: ```console -❯ ./mvnw verify +provider ❯ ./mvnw verify <<< Omitted >>> From bfacd9cf8941003ca90cdd90c738ecaa22306d75 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 16:25:06 +1100 Subject: [PATCH 18/29] chore: update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8331bf2..354bab3 100644 --- a/README.md +++ b/README.md @@ -565,7 +565,7 @@ In `consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductSer Let's run and generate an updated pact file on the consumer: ```console -❯ ./mvnw verify +consumer ❯ ./mvnw verify <<< Omitted >>> @@ -592,7 +592,7 @@ Copy the updated contract located in `consumer/target/pacts/ProductCatalogue-Pro Run the command: ```console -❯ ./mvnw verify +provider ❯ ./mvnw verify <<< Omitted >>> From 3f05a1b7a7a8a016932c7a333ac1c847a6ead5d4 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 16:27:04 +1100 Subject: [PATCH 19/29] chore: update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 354bab3..ef1e648 100644 --- a/README.md +++ b/README.md @@ -698,7 +698,7 @@ Notice that our new tests look almost identical to our previous tests, and only _response_ - the HTTP request expectations are exactly the same. ```console -❯ ./mvnw verify +consumer ❯ ./mvnw verify <<< Omitted >>> @@ -721,7 +721,7 @@ _response_ - the HTTP request expectations are exactly the same. What does our provider have to say about this new test. Again, copy the updated pact file into the provider's pact directory and run the command: ```console -❯ ./mvnw verify +provider ❯ ./mvnw verify <<< Omitted >>> From f7bada7a9abb194e67fbb2796514d4ed94fca728 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 15:51:27 +1100 Subject: [PATCH 20/29] chore: update readme --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 62bf5f7..c544270 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ If running this as a team workshop format, you may want to take a look through t - JDK 8 or above - Maven 3 +- Docker for step 11 ## Scenario @@ -76,8 +77,14 @@ public class ProductServiceClient { } ``` -After forking or cloning the repository, we need to build the app and install the dependencies with `./mvnw verify`. -We can run the app with `java -jar target/product-catalogue-0.0.1-SNAPSHOT.jar`. +After forking or cloning the repository, we need to build the app and install the dependencies. Run the following +in the `consumer` sub-directory: + +```console +/consumer ❯ ./mvnw verify +``` + +We can run the app with `/consumer ❯ java -jar target/product-catalogue-0.0.1-SNAPSHOT.jar`. Accessing the URL for the app in the browser gives us a 500 error page as the downstream service is not running. You will also see an exception in the Springboot console output. From f6fe2b4a8102067e60e2b4dbdd6ea3a11cb3d3ee Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 15:52:39 +1100 Subject: [PATCH 21/29] chore: update readme --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c544270..e5998b8 100644 --- a/README.md +++ b/README.md @@ -81,10 +81,14 @@ After forking or cloning the repository, we need to build the app and install th in the `consumer` sub-directory: ```console -/consumer ❯ ./mvnw verify +consumer ❯ ./mvnw verify ``` -We can run the app with `/consumer ❯ java -jar target/product-catalogue-0.0.1-SNAPSHOT.jar`. +We can run the app with + +```console +consumer ❯ java -jar target/product-catalogue-0.0.1-SNAPSHOT.jar +``` Accessing the URL for the app in the browser gives us a 500 error page as the downstream service is not running. You will also see an exception in the Springboot console output. From f6a8eea088eaa4dde32ed34536707c2981c905e5 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 16:00:40 +1100 Subject: [PATCH 22/29] chore: update readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e5998b8..f2bc362 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ You can see the client interface test we created in `consumer/src/test/java/io/p Let's run this test and see it all pass: ```console -❯ ./mvnw verify +consumer ❯ ./mvnw verify [INFO] Scanning for projects... [INFO] [INFO] -----------------< io.pact.workshop:product-catalogue >----------------- @@ -200,7 +200,7 @@ Meanwhile, our provider team has started building out their API in parallel. Let ```console # Terminal 1 -❯ mvn spring-boot:run +consumer ❯ mvn spring-boot:run <<< Omitted >>> @@ -227,7 +227,7 @@ Meanwhile, our provider team has started building out their API in parallel. Let ```console # Terminal 2 -> mvn spring-boot:run +provider ❯ mvn spring-boot:run <<< Omitted >>> From cd2810fed6f12fc9e73511fb5d4bbff17a9495e1 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 16:14:30 +1100 Subject: [PATCH 23/29] chore: update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f2bc362..bb81cc1 100644 --- a/README.md +++ b/README.md @@ -383,7 +383,7 @@ Running this test also passes, but it creates a pact file which we can use to va provider side, and have conversation around. ```console -❯ ./mvnw verify +consumer ❯ ./mvnw verify [INFO] Scanning for projects... [INFO] [INFO] -----------------< io.pact.workshop:product-catalogue >----------------- From 3a52b6b6892b3f1c253d4861415e1ffd6d6b6ea0 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 16:22:28 +1100 Subject: [PATCH 24/29] chore: update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb81cc1..7a1392d 100644 --- a/README.md +++ b/README.md @@ -486,7 +486,7 @@ provider is and where the pact files are. We also set the test target to point t We now need to validate the pact generated by the consumer is valid by running the test, which should fail: ```console -❯ ./mvnw verify +provider ❯ ./mvnw verify <<< Omitted >>> From 584ebf5ca6e1a12680f104cda2c21308dad1b171 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 16:25:06 +1100 Subject: [PATCH 25/29] chore: update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7a1392d..8bf095a 100644 --- a/README.md +++ b/README.md @@ -565,7 +565,7 @@ In `consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductSer Let's run and generate an updated pact file on the consumer: ```console -❯ ./mvnw verify +consumer ❯ ./mvnw verify <<< Omitted >>> @@ -592,7 +592,7 @@ Copy the updated contract located in `consumer/target/pacts/ProductCatalogue-Pro Run the command: ```console -❯ ./mvnw verify +provider ❯ ./mvnw verify <<< Omitted >>> From 9889fe983d8ec59ab78832b3fade94f1465a4c19 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 16:27:04 +1100 Subject: [PATCH 26/29] chore: update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8bf095a..9136ca1 100644 --- a/README.md +++ b/README.md @@ -698,7 +698,7 @@ Notice that our new tests look almost identical to our previous tests, and only _response_ - the HTTP request expectations are exactly the same. ```console -❯ ./mvnw verify +consumer ❯ ./mvnw verify <<< Omitted >>> @@ -721,7 +721,7 @@ _response_ - the HTTP request expectations are exactly the same. What does our provider have to say about this new test. Again, copy the updated pact file into the provider's pact directory and run the command: ```console -❯ ./mvnw verify +provider ❯ ./mvnw verify <<< Omitted >>> From 14102e323faa50905ab550158c297afa808b0f0d Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 5 Mar 2021 16:30:10 +1100 Subject: [PATCH 27/29] chore: update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9136ca1..86a7dce 100644 --- a/README.md +++ b/README.md @@ -867,7 +867,7 @@ Let's open up our provider Pact verification test in `provider/src/test/java/io/ Let's see how we go now: ```console -❯ ./mvnw verify +provider ❯ ./mvnw verify <<< Omitted >>> From 81e21dcbb7425e96114efe14001424beac844b77 Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Tue, 30 Jan 2024 18:10:03 +0000 Subject: [PATCH 28/29] chore(deps): pact-jvm 4.6.5 + java17 + springboot 3.1.x --- .github/workflows/test.yml | 33 +++++++++++++++++++ .java-version | 1 + README.md | 33 ++++++++++--------- consumer/pom.xml | 22 ++++++------- .../clients/ProductServiceClientPactTest.java | 10 +++--- provider/application.properties | 1 + provider/pom.xml | 19 ++++++----- .../product_service/products/Product.java | 4 +-- .../product_service/PactVerificationTest.java | 2 +- 9 files changed, 81 insertions(+), 44 deletions(-) create mode 100644 .github/workflows/test.yml create mode 100644 .java-version create mode 100644 provider/application.properties diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..65805f2 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,33 @@ +name: Maven CI + +on: + push: + branches: + - step7 + pull_request: + branches: + - step7 + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Set up JDK + uses: actions/setup-java@v2 + with: + java-version: '17' + distribution: 'temurin' + + - name: Consumer - Pact tests + run: ./mvnw verify + working-directory: consumer + + - name: Consumer - Move Contracts to Provider + run: cp consumer/target/pacts/ProductCatalogue-ProductService.json provider/pacts + + - name: Provider - Pact verification + run: ./mvnw verify + working-directory: provider \ No newline at end of file diff --git a/.java-version b/.java-version new file mode 100644 index 0000000..03b6389 --- /dev/null +++ b/.java-version @@ -0,0 +1 @@ +17.0 diff --git a/README.md b/README.md index 86a7dce..f452190 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,8 @@ If running this as a team workshop format, you may want to take a look through t ## Requirements -- JDK 8 or above -- Maven 3 +- JDK 17+ +- Maven 3+ - Docker for step 11 ## Scenario @@ -126,7 +126,8 @@ You can see the client interface test we created in `consumer/src/test/java/io/p ); Product product = productServiceClient.getProductById(10); - assertThat(product, is(equalTo(new Product(10L, "28 Degrees", "CREDIT_CARD", "v1")))); + assertThat(product, is(equalTo(new Product(10L, "28 Degrees", "CREDIT_CARD", "v1", null)))); + } ``` @@ -146,7 +147,7 @@ consumer ❯ ./mvnw verify [INFO] Building product-catalogue 0.0.1-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] -[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ product-catalogue --- +[INFO] --- maven-resources-plugin:3.3.0:resources (default-resources) @ product-catalogue --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Using 'UTF-8' encoding to copy filtered properties files. [INFO] Copying 1 resource @@ -155,7 +156,7 @@ consumer ❯ ./mvnw verify [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ product-catalogue --- [INFO] Nothing to compile - all classes are up to date [INFO] -[INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ product-catalogue --- +[INFO] --- maven-resources-plugin:3.3.0:testResources (default-testResources) @ product-catalogue --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Using 'UTF-8' encoding to copy filtered properties files. [INFO] skip non existing resourceDirectory /home/ronald/Development/Projects/Pact/pact-workshop-Maven-Springboot-JUnit5/consumer/src/test/resources @@ -181,7 +182,7 @@ consumer ❯ ./mvnw verify [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] -[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ product-catalogue --- +[INFO] --- maven-jar-plugin:3.3.0:jar (default-jar) @ product-catalogue --- [INFO] [INFO] --- spring-boot-maven-plugin:2.4.3:repackage (repackage) @ product-catalogue --- [INFO] Replacing main artifact with repackaged archive @@ -356,7 +357,7 @@ class ProductServiceClientPactTest { } @Test - @PactTestFor(pactMethod = "allProducts", port="9999") + @PactTestFor(pactMethod = "allProducts", pactVersion = PactSpecVersion.V3) void testAllProducts(MockServer mockServer) throws IOException { productServiceClient.setBaseUrl(mockServer.getUrl()); List products = productServiceClient.fetchProducts().getProducts(); @@ -365,7 +366,7 @@ class ProductServiceClientPactTest { } @Test - @PactTestFor(pactMethod = "singleProduct", port="9999") + @PactTestFor(pactMethod = "singleProduct", pactVersion = PactSpecVersion.V3) void testSingleProduct(MockServer mockServer) throws IOException { Product product = productServiceClient.getProductById(10L); assertThat(product, is(equalTo(new Product(10L, "28 Degrees", "CREDIT_CARD", "v1", "CC_001")))); @@ -390,7 +391,7 @@ consumer ❯ ./mvnw verify [INFO] Building product-catalogue 0.0.1-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] -[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ product-catalogue --- +[INFO] --- maven-resources-plugin:3.3.0:resources (default-resources) @ product-catalogue --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Using 'UTF-8' encoding to copy filtered properties files. [INFO] Copying 1 resource @@ -399,7 +400,7 @@ consumer ❯ ./mvnw verify [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ product-catalogue --- [INFO] Nothing to compile - all classes are up to date [INFO] -[INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ product-catalogue --- +[INFO] --- maven-resources-plugin:3.3.0:testResources (default-testResources) @ product-catalogue --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Using 'UTF-8' encoding to copy filtered properties files. [INFO] skip non existing resourceDirectory /home/ronald/Development/Projects/Pact/pact-workshop-Maven-Springboot-JUnit5/consumer/src/test/resources @@ -422,7 +423,7 @@ consumer ❯ ./mvnw verify [INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] -[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ product-catalogue --- +[INFO] --- maven-jar-plugin:3.3.0:jar (default-jar) @ product-catalogue --- [INFO] Building jar: /home/ronald/Development/Projects/Pact/pact-workshop-Maven-Springboot-JUnit5/consumer/target/product-catalogue-0.0.1-SNAPSHOT.jar [INFO] [INFO] --- spring-boot-maven-plugin:2.4.3:repackage (repackage) @ product-catalogue --- @@ -575,7 +576,7 @@ consumer ❯ ./mvnw verify [INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] -[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ product-catalogue --- +[INFO] --- maven-jar-plugin:3.3.0:jar (default-jar) @ product-catalogue --- [INFO] Building jar: /home/ronald/Development/Projects/Pact/pact-workshop-Maven-Springboot-JUnit5/consumer/target/product-catalogue-0.0.1-SNAPSHOT.jar [INFO] [INFO] --- spring-boot-maven-plugin:2.4.3:repackage (repackage) @ product-catalogue --- @@ -663,7 +664,7 @@ In `consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductSer } @Test - @PactTestFor(pactMethod = "noProducts") + @PactTestFor(pactMethod = "noProducts", pactVersion = PactSpecVersion.V3) void testNoProducts(MockServer mockServer) { productServiceClient.setBaseUrl(mockServer.getUrl()); ProductServiceResponse products = productServiceClient.fetchProducts(); @@ -682,7 +683,7 @@ In `consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductSer } @Test - @PactTestFor(pactMethod = "singleProductNotExists") + @PactTestFor(pactMethod = "singleProductNotExists", pactVersion = PactSpecVersion.V3) void testSingleProductNotExists(MockServer mockServer) { productServiceClient.setBaseUrl(mockServer.getUrl()); try { @@ -708,7 +709,7 @@ consumer ❯ ./mvnw verify [INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] -[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ product-catalogue --- +[INFO] --- maven-jar-plugin:3.3.0:jar (default-jar) @ product-catalogue --- [INFO] Building jar: /home/ronald/Development/Projects/Pact/pact-workshop-Maven-Springboot-JUnit5/consumer/target/product-catalogue-0.0.1-SNAPSHOT.jar [INFO] [INFO] --- spring-boot-maven-plugin:2.4.3:repackage (repackage) @ product-catalogue --- @@ -877,7 +878,7 @@ provider ❯ ./mvnw verify [INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] -[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ product-service --- +[INFO] --- maven-jar-plugin:3.3.0:jar (default-jar) @ product-service --- [INFO] Building jar: /home/ronald/Development/Projects/Pact/pact-workshop-Maven-Springboot-JUnit5/provider/target/product-service-1.0-SNAPSHOT.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS diff --git a/consumer/pom.xml b/consumer/pom.xml index 8582364..bfc42ca 100644 --- a/consumer/pom.xml +++ b/consumer/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.4.3 + 3.1.8 io.pact.workshop @@ -15,9 +15,9 @@ Product Catalogue service for Pact Workshop - 1.8 - 8 - 8 + 17 + 17 + 17 @@ -40,14 +40,14 @@ org.projectlombok lombok - 1.18.16 + 1.18.30 provided - com.github.tomakehurst - wiremock-jre8 - 2.27.2 + org.wiremock + wiremock + 3.0.1 test @@ -68,20 +68,20 @@ au.com.dius.pact.consumer junit5 - 4.1.7 + 4.6.5 test org.apache.commons commons-collections4 - 4.1 + 4.4 com.squareup.okhttp3 okhttp - 4.9.1 + 4.12.0 diff --git a/consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientPactTest.java b/consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientPactTest.java index 33e6bf4..bb06b59 100644 --- a/consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientPactTest.java +++ b/consumer/src/test/java/io/pact/workshop/product_catalogue/clients/ProductServiceClientPactTest.java @@ -7,6 +7,7 @@ import au.com.dius.pact.consumer.junit5.PactTestFor; import au.com.dius.pact.core.model.RequestResponsePact; import au.com.dius.pact.core.model.annotations.Pact; +import au.com.dius.pact.core.model.PactSpecVersion; // required for v4.6.x to set pactVersion import io.pact.workshop.product_catalogue.models.Product; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -14,7 +15,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.web.client.HttpClientErrorException; -import java.io.IOException; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; @@ -52,7 +52,7 @@ public RequestResponsePact allProducts(PactDslWithProvider builder) { } @Test - @PactTestFor(pactMethod = "allProducts") + @PactTestFor(pactMethod = "allProducts", pactVersion = PactSpecVersion.V3) void testAllProducts(MockServer mockServer) { productServiceClient.setBaseUrl(mockServer.getUrl()); List products = productServiceClient.fetchProducts().getProducts(); @@ -80,7 +80,7 @@ public RequestResponsePact singleProduct(PactDslWithProvider builder) { } @Test - @PactTestFor(pactMethod = "singleProduct") + @PactTestFor(pactMethod = "singleProduct", pactVersion = PactSpecVersion.V3) void testSingleProduct(MockServer mockServer) { productServiceClient.setBaseUrl(mockServer.getUrl()); Product product = productServiceClient.getProductById(10L); @@ -102,7 +102,7 @@ public RequestResponsePact noProducts(PactDslWithProvider builder) { } @Test - @PactTestFor(pactMethod = "noProducts") + @PactTestFor(pactMethod = "noProducts", pactVersion = PactSpecVersion.V3) void testNoProducts(MockServer mockServer) { productServiceClient.setBaseUrl(mockServer.getUrl()); ProductServiceResponse products = productServiceClient.fetchProducts(); @@ -121,7 +121,7 @@ public RequestResponsePact singleProductNotExists(PactDslWithProvider builder) { } @Test - @PactTestFor(pactMethod = "singleProductNotExists") + @PactTestFor(pactMethod = "singleProductNotExists", pactVersion = PactSpecVersion.V3) void testSingleProductNotExists(MockServer mockServer) { productServiceClient.setBaseUrl(mockServer.getUrl()); try { diff --git a/provider/application.properties b/provider/application.properties new file mode 100644 index 0000000..4d2c43a --- /dev/null +++ b/provider/application.properties @@ -0,0 +1 @@ +spring.jpa.defer-datasource-initialization=true diff --git a/provider/pom.xml b/provider/pom.xml index 46f5c2f..6b784ac 100644 --- a/provider/pom.xml +++ b/provider/pom.xml @@ -6,7 +6,7 @@ org.springframework.boot spring-boot-starter-parent - 2.4.3 + 3.1.8 io.pact.workshop @@ -14,11 +14,12 @@ 1.0-SNAPSHOT Product Service for Pact Workshop - - 1.8 - 8 - 8 - + + 17 + 17 + 17 + + @@ -46,7 +47,7 @@ org.projectlombok lombok - 1.18.16 + 1.18.30 provided @@ -60,13 +61,13 @@ org.apache.commons commons-collections4 - 4.1 + 4.4 au.com.dius.pact.provider junit5spring - 4.1.17 + 4.6.5 test diff --git a/provider/src/main/java/io/pact/workshop/product_service/products/Product.java b/provider/src/main/java/io/pact/workshop/product_service/products/Product.java index 8fe430e..9c8b651 100644 --- a/provider/src/main/java/io/pact/workshop/product_service/products/Product.java +++ b/provider/src/main/java/io/pact/workshop/product_service/products/Product.java @@ -4,8 +4,8 @@ import lombok.Data; import lombok.NoArgsConstructor; -import javax.persistence.Entity; -import javax.persistence.Id; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; @Entity @Data diff --git a/provider/src/test/java/io/pact/workshop/product_service/PactVerificationTest.java b/provider/src/test/java/io/pact/workshop/product_service/PactVerificationTest.java index 9775632..2c0ef12 100644 --- a/provider/src/test/java/io/pact/workshop/product_service/PactVerificationTest.java +++ b/provider/src/test/java/io/pact/workshop/product_service/PactVerificationTest.java @@ -14,7 +14,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; import java.util.Arrays; import java.util.Map; From af5b64f75655d6ba228f94da6befbd53ad111f22 Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Tue, 30 Jan 2024 18:32:48 +0000 Subject: [PATCH 29/29] docs: update step3 code snippet --- README.md | 66 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 5a8d2fe..317dfc4 100644 --- a/README.md +++ b/README.md @@ -321,57 +321,59 @@ class ProductServiceClientPactTest { public RequestResponsePact allProducts(PactDslWithProvider builder) { return builder .given("products exists") - .uponReceiving("get all products") - .path("/products") + .uponReceiving("get all products") + .path("/products") .willRespondWith() - .status(200) - .body( - new PactDslJsonBody() - .minArrayLike("products", 1, 2) - .integerType("id", 9L) - .stringType("name", "Gem Visa") - .stringType("type", "CREDIT_CARD") - .closeObject() - .closeArray() - ) + .status(200) + .body( + new PactDslJsonBody() + .minArrayLike("products", 1, 2) + .integerType("id", 9L) + .stringType("name", "Gem Visa") + .stringType("type", "CREDIT_CARD") + .closeObject() + .closeArray() + ) .toPact(); } + @Test + @PactTestFor(pactMethod = "allProducts", pactVersion = PactSpecVersion.V3) + void testAllProducts(MockServer mockServer) { + productServiceClient.setBaseUrl(mockServer.getUrl()); + List products = productServiceClient.fetchProducts().getProducts(); + assertThat(products, hasSize(2)); + assertThat(products.get(0), is(equalTo(new Product(9L, "Gem Visa", "CREDIT_CARD", null, null)))); + } + @Pact(consumer = "ProductCatalogue") public RequestResponsePact singleProduct(PactDslWithProvider builder) { return builder .given("product with ID 10 exists", "id", 10) .uponReceiving("get product with ID 10") - .path("/products/10") + .path("/products/10") .willRespondWith() - .status(200) - .body( - new PactDslJsonBody() - .integerType("id", 10L) - .stringType("name", "28 Degrees") - .stringType("type", "CREDIT_CARD") - .stringType("code", "CC_001") - .stringType("version", "v1") - ) + .status(200) + .body( + new PactDslJsonBody() + .integerType("id", 10L) + .stringType("name", "28 Degrees") + .stringType("type", "CREDIT_CARD") + .stringType("code", "CC_001") + .stringType("version", "v1") + ) .toPact(); } - @Test - @PactTestFor(pactMethod = "allProducts", pactVersion = PactSpecVersion.V3) - void testAllProducts(MockServer mockServer) throws IOException { - productServiceClient.setBaseUrl(mockServer.getUrl()); - List products = productServiceClient.fetchProducts().getProducts(); - assertThat(products, hasSize(2)); - assertThat(products.get(0), is(equalTo(new Product(9L, "Gem Visa", "CREDIT_CARD", null, null)))); - } - @Test @PactTestFor(pactMethod = "singleProduct", pactVersion = PactSpecVersion.V3) - void testSingleProduct(MockServer mockServer) throws IOException { + void testSingleProduct(MockServer mockServer) { + productServiceClient.setBaseUrl(mockServer.getUrl()); Product product = productServiceClient.getProductById(10L); assertThat(product, is(equalTo(new Product(10L, "28 Degrees", "CREDIT_CARD", "v1", "CC_001")))); } } + ```