chore: updated readme with array contains matcher
authorRonald Holshausen <rholshausen@dius.com.au>
Mon, 9 Nov 2020 03:55:16 +0000 (14:55 +1100)
committerRonald Holshausen <rholshausen@dius.com.au>
Mon, 9 Nov 2020 03:55:16 +0000 (14:55 +1100)
README.md

index e252ebb..9ad63b5 100644 (file)
--- a/README.md
+++ b/README.md
@@ -114,3 +114,152 @@ the actual URL to use in the consumer test, and a regular expression matcher tha
 verification test.
 
 To show this working, the consumer Pact test has the mock server running on port 9000, while the provider will be running on port 8080.
+
+### Dealing with hypermedia formats like Siren actions
+
+Siren takes hypermedia links one step further by introducing resource actions. These encode the URL, HTTP method and
+optionally any required parameters needed to make the requests for the actions supported by the resource.
+
+The problem could then arise that the consumer make only use a few actions provided by the provider. We would want to
+ensure that these actions are present in the list for the resource, and ignore the ones we are not using. The other issue
+is that our tests should not be dependent on the order of the actions.
+
+This is where the "array contains" matcher can help. It will allow us to match the resource actions for the ones we are
+using, and ignore the others. It will also not depend on the order the actions are returned.
+
+This is the actions for the order resource in the provider:
+
+```json
+{
+  "actions": [
+        {
+          "name": "update",
+          "method": "PUT",
+          "href": "http://localhost:8080/orders/6774860028109588394"
+        },
+        {
+          "name": "delete",
+          "method": "DELETE",
+          "href": "http://localhost:8080/orders/6774860028109588394"
+        },
+        {
+          "name": "changeStatus",
+          "method": "PUT",
+          "href": "http://localhost:8080/orders/6774860028109588394/status"
+        }
+  ]
+}
+```
+
+For example, in the consumer test we can specify:
+
+```js
+"actions": arrayContaining(
+  {
+    "name": "update",
+    "method": "PUT",
+    "href": url("http://localhost:9000", ["orders", regex("\\d+", "1234")])
+  },
+  {
+    "name": "delete",
+    "method": "DELETE",
+    "href": url("http://localhost:9000", ["orders", regex("\\d+", "1234")])
+  }
+)
+```
+
+This will match the actions if they contain the update and delete actions. it will ignore the other actions.
+
+You can see this in work if you remove one of the controller methods in the provider. For instance, if we commented out
+the delete endpoint, and then run the pact verification in the provider, we get this error:
+
+```console
+$ ./gradlew pactverify
+
+> Task :startServer
+
+  .   ____          _            __ _ _
+ /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
+  '  |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot ::        (v2.3.4.RELEASE)
+
+2020-11-09 14:53:32.046  INFO 39485 --- [           main] i.p.e.s.SirenProviderApplication         : Starting SirenProviderApplication on ronald-P95xER with PID 39485 (/home/ronald/Development/Projects/Pact/example-siren/provider/build/libs/siren-provider-0.0.1.jar started by ronald in /home/ronald/Development/Projects/Pact/example-siren/provider)
+2020-11-09 14:53:32.048  INFO 39485 --- [           main] i.p.e.s.SirenProviderApplication         : No active profile set, falling back to default profiles: default
+2020-11-09 14:53:32.797  INFO 39485 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
+2020-11-09 14:53:32.808  INFO 39485 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
+2020-11-09 14:53:32.808  INFO 39485 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.38]
+2020-11-09 14:53:32.870  INFO 39485 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
+2020-11-09 14:53:32.870  INFO 39485 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 759 ms
+2020-11-09 14:53:33.071  INFO 39485 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
+2020-11-09 14:53:33.221  INFO 39485 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
+2020-11-09 14:53:33.229  INFO 39485 --- [           main] i.p.e.s.SirenProviderApplication         : Started SirenProviderApplication in 1.53 seconds (JVM running for 1.903)
+java -jar /home/ronald/Development/Projects/Pact/example-siren/provider/build/libs/siren-provider-0.0.1.jar is ready.
+
+> Task :pactVerify_Siren_Order_Provider FAILED
+
+Verifying a pact between Siren Consumer and Siren Order Provider
+  [Using File /home/ronald/Development/Projects/Pact/example-siren/consumer/pacts/Siren Order Provider-Siren Order Service.json]
+  get root
+    returns a response which
+      has status code 200 (OK)
+      has a matching body (OK)
+  get all orders
+    returns a response which
+      has status code 200 (OK)
+      has a matching body (FAILED)
+  delete order
+    returns a response which
+      has status code 200 (FAILED)
+      has a matching body (OK)
+
+NOTE: Skipping publishing of verification results as it has been disabled (pact.verifier.publishResults is not 'true')
+
+
+Failures:
+
+1) Verifying a pact between Siren Consumer and Siren Order Provider - get all orders
+
+    1.1) body: $.entities.0.actions Variant at index 1 ({"href":http://localhost:9000/orders/1234,"method":DELETE,"name":delete}) was not found in the actual list
+
+        [
+          {
+        -    "href": "http://localhost:9000/orders/1234",
+        +    "href": "http://localhost:8080/orders/7779028774458252624",
+            "method": "PUT",
+            "name": "update"
+          },
+          {
+        -    "href": "http://localhost:9000/orders/1234",
+        -    "method": "DELETE",
+        -    "name": "delete"
+        +    "href": "http://localhost:8080/orders/7779028774458252624/status",
+        +    "method": "PUT",
+        +    "name": "changeStatus"
+          }
+        ]
+
+
+    1.2) status: expected status of 200 but was 405
+
+
+
+FAILURE: Build failed with an exception.
+
+* What went wrong:
+There were 2 non-pending pact failures for provider Siren Order Provider
+
+* Try:
+Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
+
+* Get more help at https://help.gradle.org
+
+Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
+Use '--warning-mode all' to show the individual deprecation warnings.
+See https://docs.gradle.org/6.6.1/userguide/command_line_interface.html#sec:command_line_warnings
+
+BUILD FAILED in 4s
+8 actionable tasks: 6 executed, 2 up-to-date
+```