Spring Cloud Contract Stub Runner
One of the issues that you might encounter while using Spring Cloud Contract Verifier is passing the generated WireMock JSON stubs from the server side to the client side (or to various clients). The same takes place in terms of client-side generation for messaging.
Copying the JSON files and setting the client side for messaging manually is out of the question. That is why we introduced Spring Cloud Contract Stub Runner. It can automatically download and run the stubs for you.
Snapshot versions
Add the additional snapshot repository to your build.gradle file to use snapshot
versions, which are automatically uploaded after every successful build:
Publishing Stubs as JARs
The easiest approach would be to centralize the way stubs are kept. For example, you can keep them as jars in a Maven repository.
| For both Maven and Gradle, the setup comes ready to work. However, you can customize it if you want to. |
<!-- First disable the default jar setup in the properties section -->
<!-- Next add the assembly plugin to your build -->
<!-- Finally setup your assembly. Below you can find the contents of src/main/assembly/stub.xml -->
Common
This section briefly describes common properties, including:
Common Properties for JUnit and Spring
You can set repetitive properties by using system properties or Spring configuration properties. Here are their names with their default values:
| Property name | Default value | Description |
|---|---|---|
stubrunner.minPort |
10000 |
Minimum value of a port for a started WireMock with stubs. |
stubrunner.maxPort |
15000 |
Maximum value of a port for a started WireMock with stubs. |
stubrunner.repositoryRoot |
Maven repo URL. If blank, then call the local maven repo. |
|
stubrunner.classifier |
stubs |
Default classifier for the stub artifacts. |
stubrunner.stubsMode |
CLASSPATH |
The way you want to fetch and register the stubs |
stubrunner.ids |
Array of Ivy notation stubs to download. |
|
stubrunner.username |
Optional username to access the tool that stores the JARs with stubs. |
|
stubrunner.password |
Optional password to access the tool that stores the JARs with stubs. |
|
stubrunner.stubsPerConsumer |
false |
Set to |
stubrunner.consumerName |
If you want to use a stub for each consumer and want to override the consumer name just change this value. |
Stub Runner Stubs IDs
You can provide the stubs to download via the stubrunner.ids system property. They
follow this pattern:
groupId:artifactId:version:classifier:port
Note that version, classifier and port are optional.
-
If you do not provide the
port, a random one will be picked. -
If you do not provide the
classifier, the default is used. (Note that you can pass an empty classifier this way:groupId:artifactId:version:). -
If you do not provide the
version, then the+will be passed and the latest one is downloaded.
port means the port of the WireMock server.
| Starting with version 1.0.4, you can provide a range of versions that you would like the Stub Runner to take into consideration. You can read more about the Aether versioning ranges here. |
Stub Runner Docker
We’re publishing a spring-cloud/spring-cloud-contract-stub-runner Docker image
that will start the standalone version of Stub Runner.
If you want to learn more about the basics of Maven, artifact ids, group ids, classifiers and Artifact Managers, just click here [docker-project].
How to use it
Just execute the docker image. You can pass any of the Common Properties for JUnit and Spring
as environment variables. The convention is that all the
letters should be upper case. The camel case notation should
and the dot (.) should be separated via underscore (_). E.g.
the stubrunner.repositoryRoot property should be represented
as a STUBRUNNER_REPOSITORY_ROOT environment variable.
Example of client side usage in a non JVM project
We’d like to use the stubs created in this [docker-server-side] step.
Let’s assume that we want to run the stubs on port 9876. The NodeJS code
is available here:
$ git clone https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs
$ cd bookstore
Let’s run the Stub Runner Boot application with the stubs.
# Provide the Spring Cloud Contract Docker version
$ SC_CONTRACT_DOCKER_VERSION="..."
# The IP at which the app is running and Docker container can reach it
$ APP_IP="192.168.0.100"
# Spring Cloud Contract Stub Runner properties
$ STUBRUNNER_PORT="8083"
# Stub coordinates 'groupId:artifactId:version:classifier:port'
$ STUBRUNNER_IDS="com.example:bookstore:0.0.1.RELEASE:stubs:9876"
$ STUBRUNNER_REPOSITORY_ROOT="http://${APP_IP}:8081/artifactory/libs-release-local"
# Run the docker with Stub Runner Boot
$ docker run --rm -e "STUBRUNNER_IDS=${STUBRUNNER_IDS}" -e "STUBRUNNER_REPOSITORY_ROOT=${STUBRUNNER_REPOSITORY_ROOT}" -e "STUBRUNNER_STUBS_MODE=REMOTE" -p "${STUBRUNNER_PORT}:${STUBRUNNER_PORT}" -p "9876:9876" springcloud/spring-cloud-contract-stub-runner:"${SC_CONTRACT_DOCKER_VERSION}"
What’s happening is that
-
a standalone Stub Runner application got started
-
it downloaded the stub with coordinates
com.example:bookstore:0.0.1.RELEASE:stubson port9876 -
it got downloaded from Artifactory running at
http://192.168.0.100:8081/artifactory/libs-release-local -
after a while Stub Runner will be running on port
8083 -
and the stubs will be running at port
9876
On the server side we built a stateful stub. Let’s use curl to assert that the stubs are setup properly.
# let's execute the first request (no response is returned)
$ curl -H "Content-Type:application/json" -X POST --data '{ "title" : "Title", "genre" : "Genre", "description" : "Description", "author" : "Author", "publisher" : "Publisher", "pages" : 100, "image_url" : "https://d213dhlpdb53mu.cloudfront.net/assets/pivotal-square-logo-41418bd391196c3022f3cd9f3959b3f6d7764c47873d858583384e759c7db435.svg", "buy_url" : "https://pivotal.io" }' http://localhost:9876/api/books
# Now time for the second request
$ curl -X GET http://localhost:9876/api/books
# You will receive contents of the JSON
If you want use the stubs that you have built locally, on your host,
then you should pass the environment variable -e STUBRUNNER_STUBS_MODE=LOCAL and mount
the volume of your local m2 -v "${HOME}/.m2/:/root/.m2:ro"
|