Saturday, July 27, 2019

PACT Consumer Driven Contract Testing: how to allow any body in the response


Consumer Driven Contract testing is a way to ensure that services (such as an API provider and a client) can communicate with each other. Without contract testing, the only way to know that services can communicate is by using expensive and brittle integration tests.
PACT is a contract testing tool.  


For response matching you want to be as loose as possible with the matching for the response (will_respond_with(...)) though. This stops the tests being brittle on the provider side.
 Most of the time you don't care about the exact values of the (JSON or XML) response, but you do care about the types of the values, e.g a string or a number.
In that case you'll be using 'type matching'.

Sadly for JVM matchers there's no such handy method that with one invocation makes sure only types are validated, as is for example with Ruby/Groovy/Javascript/Node: Pact::SomethingLike.
Not much documentation on the Java/JVM matchers can be found at the official Pact site itself. Mostly the examples are for Ruby/Groovy/Javascript/Node.

For  the Java and Virtual Machine integration you'd use pact-jvm with matchers like .stringType() for the body using the PACT DSL or this lambda extension.

But hard to find was how to specify allowing either an empty body in the response or any data in the body in the response, while the consumer does not require a body at all (or in other words: is fine with an empty body or any fields in it).
Solution: for that you need to completely omit the .body() in the consumer contract definition.
If you specify a .body(new PactDslJsonBody()), the contract generated matcher will specify "body" : {}, and therefor requiring an empty body. And if then the provider (test) generates one or more fields in the response, you'll see this as the message in the failing test:


Expected an empty Map but received Map(..... fields added by provider ...)


So full example which accepts an empty body or a body with elements in it:

.consumer("Some Consumer")
.hasPactWith("Some Provider")
.given("a certain state on the provider")
    .uponReceiving("a request for something")
        .path("/hello")
        .method("POST")
.toPact()


Tuesday, July 9, 2019

Maven Failsafe plugin build error: SurefireBooterForkException: The forked VM terminated without properly saying goodbye. VM crash or System.exit called?


When you get this exception during running mvn clean verify, which executes both the Surefire and Failsafe plugin (for which the last one uses the Surefire plugin!):

SurefireBooterForkException: The forked VM terminated without properly saying goodbye. VM crash or System.exit called?

it can mean several things. For example as the message says maybe somewhere in your integration tests you call System.exit, which you shouldn't do. That one is easy to find. Also this Stackoverflow post covers that plus some other options, like shortage of memory.

It has also higher chance on happening when using the docker-maven image and 3.x-openjdk-8 or 3.y-openjdk-10.

But if that doesn't fix it, what then?  Then due to this issue you probably have to add this property in your pom.xml in the configuration of both the Surefire and the Failsafe plugin:

<usesystemclassloader>false</usesystemclassloader>

Thus not only for the Failsafe plugin, for both! :)

PS: adding that configuration property also is a workaround for https://issues.apache.org/jira/browse/SUREFIRE-1588, also reported here: https://stackoverflow.com/questions/50661648/spring-boot-fails-to-run-maven-surefire-plugin-classnotfoundexception-org-apache/50661649#50661649