Merge branch '1.1.x'
This commit is contained in:
618
README.adoc
618
README.adoc
@@ -20,7 +20,7 @@ http://cloud-samples.spring.io/spring-cloud-contract-samples/workshops.html[this
|
||||
|
||||
=== Spring Cloud Contract Verifier
|
||||
|
||||
=== Introduction
|
||||
== Spring Cloud Contract Verifier Introduction
|
||||
|
||||
TIP: The Accurest project was initially started by Marcin Grzejszczak and Jakub Kubrynski (http://codearte.io[codearte.io])
|
||||
|
||||
@@ -35,13 +35,13 @@ Full test is generated by Spring Cloud Contract Verifier.
|
||||
|
||||
Spring Cloud Contract Verifier moves TDD to the level of software architecture.
|
||||
|
||||
==== Why?
|
||||
=== Why?
|
||||
|
||||
Let us assume that we have a system comprising of multiple microservices:
|
||||
|
||||
image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/{branch}/docs/src/main/asciidoc/images/Deps.png[Microservices Architecture]
|
||||
|
||||
===== Testing issues
|
||||
==== Testing issues
|
||||
|
||||
If we wanted to test the application in top left corner if it can communicate with other services then we could do one of two things:
|
||||
|
||||
@@ -85,7 +85,7 @@ image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/{bra
|
||||
Spring Cloud Contract Verifier gives you the certainty that the stubs that you're using were created by the service that you're calling. Also if you can use them it means that they were
|
||||
tested against the producer's side. In other words - you can trust those stubs.
|
||||
|
||||
==== Purposes
|
||||
=== Purposes
|
||||
|
||||
The main purposes of Spring Cloud Contract Verifier with Stub Runner are:
|
||||
|
||||
@@ -99,9 +99,9 @@ Let's assume that we have a business use case of fraud check. If a user can be a
|
||||
we would assume that you would create 2 contracts. One for the positive and one for the negative fraud case.
|
||||
Contract tests are used to test contracts between applications and not to simulate full behaviour.
|
||||
|
||||
==== How
|
||||
=== How
|
||||
|
||||
===== Define the contract
|
||||
==== Define the contract
|
||||
|
||||
As consumers we need to define what exactly we want to achieve. We need to formulate our expectations. That's why we write the following contract.
|
||||
|
||||
@@ -168,7 +168,7 @@ From the Producer perspective, in the autogenerated producer-side test:
|
||||
*/
|
||||
----
|
||||
|
||||
===== Client Side
|
||||
==== Client Side
|
||||
|
||||
Spring Cloud Contract will generate stubs, which you can use during client side testing.
|
||||
You will have a WireMock instance / Messaging route up and running that simulates the service Y.
|
||||
@@ -197,7 +197,7 @@ public class LoanApplicationServiceTests {
|
||||
|
||||
After that, during the tests Spring Cloud Contract will automatically find the stubs (simulating the real service) in Maven repository and expose them on configured (or random) port.
|
||||
|
||||
===== Server Side
|
||||
==== Server Side
|
||||
|
||||
Being a service Y since you are developing your stub, you need to be sure that it's actually resembling your
|
||||
concrete implementation. You can't have a situation where your stub acts in one way and your application on
|
||||
@@ -231,7 +231,7 @@ public void validate_shouldMarkClientAsFraud() throws Exception {
|
||||
}
|
||||
----
|
||||
|
||||
==== Step by step guide to CDC
|
||||
=== Step by step guide to CDC
|
||||
|
||||
Let's take an example of Fraud Detection and Loan Issuance process. The business scenario is such that we want to issue loans to people but don't want them to steal the money from us. The current implementation of our system grants loans to everybody.
|
||||
|
||||
@@ -248,7 +248,7 @@ The https://github.com/spring-cloud/spring-cloud-contract/tree/{branch}/samples/
|
||||
TIP: In this case the ownership of the contracts lays on the producer side. It means that physically
|
||||
all the contract are present in the producer's repository
|
||||
|
||||
===== Technical note
|
||||
==== Technical note
|
||||
|
||||
If using the *SNAPSHOT* / *Milestone* / *Release Candidate* versions please add the following section to your
|
||||
|
||||
@@ -321,7 +321,7 @@ repositories {
|
||||
}
|
||||
----
|
||||
|
||||
===== Consumer side (Loan Issuance)
|
||||
==== Consumer side (Loan Issuance)
|
||||
|
||||
As a developer of the Loan Issuance service (a consumer of the Fraud Detection server):
|
||||
|
||||
@@ -601,7 +601,7 @@ What we did until now is an iterative process. We can play around with the contr
|
||||
|
||||
Once we're satisfied with the results and the test passes publish a PR to the server side. Currently the consumer side work is done.
|
||||
|
||||
===== Producer side (Fraud Detection server)
|
||||
==== Producer side (Fraud Detection server)
|
||||
|
||||
As a developer of the Fraud Detection server (a server to the Loan Issuance service):
|
||||
|
||||
@@ -762,7 +762,7 @@ git push origin master
|
||||
|
||||
Then we assume that your CI would run sth like `./mvnw clean deploy` which would publish both the application and the stub artifcats.
|
||||
|
||||
===== Consumer side (Loan Issuance) final step
|
||||
==== Consumer side (Loan Issuance) final step
|
||||
|
||||
As a developer of the Loan Issuance service (a consumer of the Fraud Detection server):
|
||||
|
||||
@@ -789,599 +789,36 @@ stubrunner:
|
||||
|
||||
And that's it!
|
||||
|
||||
==== Dependencies
|
||||
=== Dependencies
|
||||
|
||||
The best way to add the dependencies is to just use the proper `starter` dependency.
|
||||
|
||||
For `stub-runner` use `spring-cloud-starter-stub-runner` and when you're using a plugin just add
|
||||
`spring-cloud-starter-contract-verifier`.
|
||||
|
||||
==== Additional links
|
||||
=== Additional links
|
||||
|
||||
Below you can find some resources related to Spring Cloud Contract Verifier and Stub Runner. Note that some can be outdated since the Spring Cloud Contract Verifier project
|
||||
is under constant development.
|
||||
|
||||
===== Spring Cloud Contract video
|
||||
==== Spring Cloud Contract video
|
||||
|
||||
You can check out the video from the Warsaw JUG about Spring Cloud Contract:
|
||||
|
||||
video::sAAklvxmPmk[youtube,start=538,width=640,height=480]
|
||||
|
||||
===== Readings
|
||||
==== Readings
|
||||
|
||||
- http://www.slideshare.net/MarcinGrzejszczak/stick-to-the-rules-consumer-driven-contracts-201507-confitura[Slides from Marcin Grzejszczak's talk about Accurest]
|
||||
- http://toomuchcoding.com/blog/categories/accurest/[Accurest related articles from Marcin Grzejszczak's blog]
|
||||
- http://toomuchcoding.com/blog/categories/spring-cloud-contract/[Spring Cloud Contract related articles from Marcin Grzejszczak's blog]
|
||||
- http://groovy-lang.org/json.html[Groovy docs regarding JSON]
|
||||
|
||||
==== Samples
|
||||
=== Samples
|
||||
|
||||
Here you can find some https://github.com/spring-cloud-samples/spring-cloud-contract-samples[samples].
|
||||
|
||||
=== FAQ
|
||||
|
||||
==== Why use Spring Cloud Contract Verifier and not X ?
|
||||
|
||||
For the time being Spring Cloud Contract Verifier is a JVM based tool. So it could be your first pick when you're already creating
|
||||
software for the JVM. This project has a lot of really interesting features but especially quite a few of them definitely make
|
||||
Spring Cloud Contract Verifier stand out on the "market" of Consumer Driven Contract (CDC) tooling. Out of many the most interesting are:
|
||||
|
||||
- Possibility to do CDC with messaging
|
||||
- Clear and easy to use, statically typed DSL
|
||||
- Possibility to copy paste your current JSON file to the contract and only edit its elements
|
||||
- Automatic generation of tests from the defined Contract
|
||||
- Stub Runner functionality - the stubs are automatically downloaded at runtime from Nexus / Artifactory
|
||||
- Spring Cloud integration - no discovery service is needed for integration tests
|
||||
|
||||
==== What is this value(consumer(), producer()) ?
|
||||
|
||||
One of the biggest challenges related to stubs is their reusability. Only if they can be vastly used, will they serve their purpose.
|
||||
What typically makes that difficult are the hard-coded values of request / response elements. For example dates or ids.
|
||||
Imagine the following JSON request
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "2016-10-10 20:10:15",
|
||||
"id" : "9febab1c-6f36-4a0b-88d6-3b6a6d81cd4a",
|
||||
"body" : "foo"
|
||||
}
|
||||
----
|
||||
|
||||
and JSON response
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "2016-10-10 21:10:15",
|
||||
"id" : "c4231e1f-3ca9-48d3-b7e7-567d55f0d051",
|
||||
"body" : "bar"
|
||||
}
|
||||
----
|
||||
|
||||
Imagine the pain required to set proper value of the `time` field (let's assume that this content is generated by the
|
||||
database) by changing the clock in the system or providing stub implementations of data providers. The same is related
|
||||
to the field called `id`. Will you create a stubbed implementation of UUID generator? Makes little sense...
|
||||
|
||||
So as a consumer you would like to send a request that matches any form of a time or any UUID. That way your system
|
||||
will work as usual - will generate data and you won't have to stub anything out. Let's assume that in case of the aforementioned
|
||||
JSON the most important part is the `body` field. You can focus on that and provide matching for other fields. In other words
|
||||
you would like the stub to work like this:
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "SOMETHING THAT MATCHES TIME",
|
||||
"id" : "SOMETHING THAT MATCHES UUID",
|
||||
"body" : "foo"
|
||||
}
|
||||
----
|
||||
|
||||
As far as the response goes as a consumer you need a concrete value that you can operate on. So such a JSON is valid
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "2016-10-10 21:10:15",
|
||||
"id" : "c4231e1f-3ca9-48d3-b7e7-567d55f0d051",
|
||||
"body" : "bar"
|
||||
}
|
||||
----
|
||||
|
||||
As you could see in the previous sections we generate tests from contracts. So from the producer's side the situation looks
|
||||
much different. We're parsing the provided contract and in the test we want to send a real request to your endpoints.
|
||||
So for the case of a producer for the request we can't have any sort of matching. We need concrete values that the
|
||||
producer's backend can work on. Such a JSON would be a valid one:
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "2016-10-10 20:10:15",
|
||||
"id" : "9febab1c-6f36-4a0b-88d6-3b6a6d81cd4a",
|
||||
"body" : "foo"
|
||||
}
|
||||
----
|
||||
|
||||
On the other hand from the point of view of the validity of the contract the response doesn't necessarily have to
|
||||
contain concrete values of `time` or `id`. Let's say that you generate those on the producer side - again, you'd
|
||||
have to do a lot of stubbing to ensure that you always return the same values. That's why from the producer's side
|
||||
what you might want is the following response:
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "SOMETHING THAT MATCHES TIME",
|
||||
"id" : "SOMETHING THAT MATCHES UUID",
|
||||
"body" : "bar"
|
||||
}
|
||||
----
|
||||
|
||||
How can you then provide one time a matcher for the consumer and a concrete value for the producer and vice versa?
|
||||
In Spring Cloud Contract we're allowing you to provide a *dynamic value*. That means that it can differ for both
|
||||
sides of the communication. You can pass the values:
|
||||
|
||||
Either via the `value` method
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
value(consumer(...), producer(...))
|
||||
value(stub(...), test(...))
|
||||
value(client(...), server(...))
|
||||
----
|
||||
|
||||
or using the `$()` method
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
$(consumer(...), producer(...))
|
||||
$(stub(...), test(...))
|
||||
$(client(...), server(...))
|
||||
----
|
||||
|
||||
You can read more about this in the https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html#_contract_dsl[Contract DSL section].
|
||||
|
||||
Calling `value()` or `$()` tells Spring Cloud Contract that you will be passing a dynamic value.
|
||||
Inside the `consumer()` method you pass the value that should be used on the consumer side (in the generated stub).
|
||||
Inside the `producer()` method you pass the value that should be used on the producer side (in the generated test).
|
||||
|
||||
TIP: If on one side you have passed the regular expression and you haven't passed the other, then the
|
||||
other side will get auto-generated.
|
||||
|
||||
Most often you will use that method together with the `regex` helper method. E.g. `consumer(regex('[0-9]{10}'))`.
|
||||
|
||||
To sum it up the contract for the aforementioned scenario would look more or less like this (the regular expression
|
||||
for time and UUID are simplified and most likely invalid but we want to keep things very simple in this example):
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
org.springframework.cloud.contract.spec.Contract.make {
|
||||
request {
|
||||
method 'GET'
|
||||
url '/someUrl'
|
||||
body([
|
||||
time : value(consumer(regex('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-2][0-9]-[0-5][0-9]-[0-5][0-9]')),
|
||||
id: value(consumer(regex('[0-9a-zA-z]{8}-[0-9a-zA-z]{4}-[0-9a-zA-z]{4}-[0-9a-zA-z]{12}'))
|
||||
body: "foo"
|
||||
])
|
||||
}
|
||||
response {
|
||||
status 200
|
||||
body([
|
||||
time : value(producer(regex('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-2][0-9]-[0-5][0-9]-[0-5][0-9]')),
|
||||
id: value([producer(regex('[0-9a-zA-z]{8}-[0-9a-zA-z]{4}-[0-9a-zA-z]{4}-[0-9a-zA-z]{12}'))
|
||||
body: "bar"
|
||||
])
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
IMPORTANT: Please read the http://groovy-lang.org/json.html[Groovy docs related to JSON] to understand how to
|
||||
properly structure the request / response bodies.
|
||||
|
||||
==== How to do Stubs versioning?
|
||||
|
||||
===== API Versioning
|
||||
|
||||
Let's try to answer a question what versioning really means. If you're referring to the API version then there are
|
||||
different approaches.
|
||||
|
||||
- use Hypermedia, links and do not version your API by any means
|
||||
- pass versions through headers / urls
|
||||
|
||||
I will not try to answer a question which approach is better. Whatever suit your needs and allows you to generate
|
||||
business value should be picked.
|
||||
|
||||
Let's assume that you do version your API. In that case you should provide as many contracts as many versions you support.
|
||||
You can create a subfolder for every version or append it to th contract name - whatever suits you more.
|
||||
|
||||
===== JAR versioning
|
||||
|
||||
If by versioning you mean the version of the JAR that contains the stubs then there are essentially two main approaches.
|
||||
|
||||
Let's assume that you're doing Continuous Delivery / Deployment which means that you're generating a new version of
|
||||
the jar each time you go through the pipeline and that jar can go to production at any time. For example your jar version
|
||||
looks like this (it got built on the 20.10.2016 at 20:15:21) :
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
1.0.0.20161020-201521-RELEASE
|
||||
----
|
||||
|
||||
In that case your generated stub jar will look like this.
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
1.0.0.20161020-201521-RELEASE-stubs.jar
|
||||
----
|
||||
|
||||
In this case you should inside your `application.yml` or `@AutoConfigureStubRunner` when referencing stubs provide the
|
||||
latest version of the stubs. You can do that by passing the `+` sign. Example
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:8080"})
|
||||
----
|
||||
|
||||
If the versioning however is fixed (e.g. `1.0.4.RELEASE` or `2.1.1`) then you have to set the concrete value of the jar
|
||||
version. Example for 2.1.1.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:2.1.1:stubs:8080"})
|
||||
----
|
||||
|
||||
===== Dev or prod stubs
|
||||
|
||||
You can manipulate the classifier to run the tests against current development version of the stubs of other services
|
||||
or the ones that were deployed to production. If you alter your build to deploy the stubs with the `prod-stubs` classifier
|
||||
once you reach production deployment then you can run tests in one case with dev stubs and one with prod stubs.
|
||||
|
||||
Example of tests using development version of stubs
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:8080"})
|
||||
----
|
||||
|
||||
Example of tests using production version of stubs
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:prod-stubs:8080"})
|
||||
----
|
||||
|
||||
You can pass those values also via properties from your deployment pipeline.
|
||||
|
||||
==== Common repo with contracts
|
||||
|
||||
Another way of storing contracts other than having them with the producer is keeping them in a common place.
|
||||
It can be related to security issues where the consumers can't clone the producer's code. Also if you keep
|
||||
contracts in a single place then you, as a producer, will know how many consumers you have and which
|
||||
consumer will you break with your local changes.
|
||||
|
||||
===== Repo structure
|
||||
|
||||
Let's assume that we have a producer with coordinates `com.example:server` and 3 consumers: `client1`,
|
||||
`client2`, `client3`. Then in the repository with common contracts you would have the following setup
|
||||
(which you can checkout https://github.com/spring-cloud/spring-cloud-contract/tree/{branch}/samples/standalone/contracts[here]:
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
├── com
|
||||
│ └── example
|
||||
│ └── server
|
||||
│ ├── client1
|
||||
│ │ └── expectation.groovy
|
||||
│ ├── client2
|
||||
│ │ └── expectation.groovy
|
||||
│ ├── client3
|
||||
│ │ └── expectation.groovy
|
||||
│ └── pom.xml
|
||||
├── mvnw
|
||||
├── mvnw.cmd
|
||||
├── pom.xml
|
||||
└── src
|
||||
└── assembly
|
||||
└── contracts.xml
|
||||
----
|
||||
|
||||
As you can see the under the slash-delimited groupid `/` artifact id folder (`com/example/server`) you have
|
||||
expectations of the 3 consumers (`client1`, `client2` and `client3`). Expectations are the standard Groovy DSL
|
||||
contract files as described throughout this documentation. This repository has to produce a JAR file that maps
|
||||
one to one to the contents of the repo.
|
||||
|
||||
Example of a `pom.xml` inside the `server` folder.
|
||||
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>server</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
<name>Server Stubs</name>
|
||||
<description>POM used to install locally stubs for consumer side</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.4.RELEASE</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<spring-cloud-contract.version>1.2.0.BUILD-SNAPSHOT</spring-cloud-contract.version>
|
||||
<spring-cloud-dependencies.version>Edgware.BUILD-SNAPSHOT</spring-cloud-dependencies.version>
|
||||
<excludeBuildFolders>true</excludeBuildFolders>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>${spring-cloud-dependencies.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
|
||||
<version>${spring-cloud-contract.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<!-- By default it would search under src/test/resources/ -->
|
||||
<contractsDirectory>${project.basedir}</contractsDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<url>https://repo.spring.io/release</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<url>https://repo.spring.io/release</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
</project>
|
||||
----
|
||||
|
||||
As you can see there are no dependencies other than the Spring Cloud Contract Maven Plugin.
|
||||
Those poms are necessary for the consumer side to run `mvn clean install -DskipTests` to locally install
|
||||
stubs of the producer project.
|
||||
|
||||
The `pom.xml` in the root folder can look like this:
|
||||
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.example.standalone</groupId>
|
||||
<artifactId>contracts</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
<name>Contracts</name>
|
||||
<description>Contains all the Spring Cloud Contracts, well, contracts. JAR used by the producers to generate tests and stubs</description>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>contracts</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<attach>true</attach>
|
||||
<descriptor>${basedir}/src/assembly/contracts.xml</descriptor>
|
||||
<!-- If you want an explicit classifier remove the following line -->
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
----
|
||||
|
||||
It's using the assembly plugin in order to build the JAR with all the contracts. Example of such setup is here:
|
||||
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
|
||||
<id>project</id>
|
||||
<formats>
|
||||
<format>jar</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${project.basedir}</directory>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<excludes>
|
||||
<exclude>**/${project.build.directory}/**</exclude>
|
||||
<exclude>mvnw</exclude>
|
||||
<exclude>mvnw.cmd</exclude>
|
||||
<exclude>.mvn/**</exclude>
|
||||
<exclude>src/**</exclude>
|
||||
</excludes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
----
|
||||
|
||||
===== Workflow
|
||||
|
||||
The workflow would look similar to the one presented in the `Step by step guide to CDC`. The only difference
|
||||
is that the producer doesn't own the contracts anymore. So the consumer and the producer have to work on
|
||||
common contracts in a common repository.
|
||||
|
||||
====== Consumer
|
||||
|
||||
When the *consumer* wants to work on the contracts offline, instead of cloning the producer code, the
|
||||
consumer team clones the common repository, goes to the required producer's folder (e.g. `com/example/server`)
|
||||
and runs `mvn clean install -DskipTests` to install locally the stubs converted from the contracts.
|
||||
|
||||
TIP: You need to have http://maven.apache.org/download.cgi[Maven installed locally]
|
||||
|
||||
====== Producer
|
||||
|
||||
As a *producer* it's enough to alter the Spring Cloud Contract Verifier to provide the URL and the dependency
|
||||
of the JAR containing the contracts:
|
||||
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
<plugin>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<contractsRepositoryUrl>http://link/to/your/nexus/or/artifactory/or/sth</contractsRepositoryUrl>
|
||||
<contractDependency>
|
||||
<groupId>com.example.standalone</groupId>
|
||||
<artifactId>contracts</artifactId>
|
||||
</contractDependency>
|
||||
</configuration>
|
||||
</plugin>
|
||||
----
|
||||
|
||||
With this setup the JAR with groupid `com.example.standalone` and artifactid `contracts` will be downloaded
|
||||
from `http://link/to/your/nexus/or/artifactory/or/sth`. It will be then unpacked in a local temporary folder
|
||||
and contracts present under the `com/example/server` will be picked as the ones used to generate the
|
||||
tests and the stubs. Due to this convention the producer team will know which consumer teams will be broken
|
||||
when some incompatible changes are done.
|
||||
|
||||
The rest of the flow looks the same.
|
||||
|
||||
==== Can I have multiple base classes for tests?
|
||||
|
||||
Yes! Check out the https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html#_different_base_classes_for_contracts[Different base classes for contracts] sections
|
||||
of either Gradle or Maven plugins.
|
||||
|
||||
==== How can I debug the request/response being sent by the generated tests client?
|
||||
|
||||
The generated tests all boil down to RestAssured in some form or fashion which relies on https://hc.apache.org/httpcomponents-client-ga/[Apache HttpClient]. HttpClient has a facility called https://hc.apache.org/httpcomponents-client-ga/logging.html#Wire_Logging[wire logging] which logs the entire request and response to HttpClient. Spring Boot has a logging https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html[common application property] for doing this sort of thing, just add this to your application properties
|
||||
[source,properties,indent=0]
|
||||
----
|
||||
logging.level.org.apache.http.wire=DEBUG
|
||||
----
|
||||
|
||||
==== How can I debug the mapping/request/response being sent by WireMock?
|
||||
|
||||
Starting from version `1.2.0` we turn on WireMock logging to
|
||||
info and the WireMock notifier to being verbose. Now you will
|
||||
exactly know what request was received by WireMock server and which
|
||||
matching response definition was picked.
|
||||
|
||||
To turn off this feature just bump WireMock logging to `ERROR`
|
||||
|
||||
[source,properties,indent=0]
|
||||
----
|
||||
logging.level.com.github.tomakehurst.wiremock=ERROR
|
||||
----
|
||||
|
||||
==== How can I see what got registered in the HTTP server stub?
|
||||
|
||||
You can use the `mappingsOutputFolder` property on `@AutoConfigureStubRunner` or `StubRunnerRule`
|
||||
to dump all mappings per artifact id. Also the port at which the given stub server was
|
||||
started will be attached.
|
||||
|
||||
==== Can I reference the request from the response?
|
||||
|
||||
Yes! With version 1.1.0 we've added such a possibility. On the HTTP stub server side we're providing support
|
||||
for this for WireMock. In case of other HTTP server stubs you'll have to implement the approach yourself.
|
||||
|
||||
==== Can I reference text from file?
|
||||
|
||||
Yes! With version 1.2.0 we've added such a possibility. It's enough to call `file(...)` method in the
|
||||
DSL and provide a path relative to where the contract lays.
|
||||
|
||||
=== Links
|
||||
|
||||
Here you can find interesting links related to Spring Cloud Contract Verifier:
|
||||
|
||||
- https://github.com/spring-cloud/spring-cloud-contract/[Spring Cloud Contract Github Repository]
|
||||
- https://github.com/spring-cloud-samples/spring-cloud-contract-samples/[Spring Cloud Contract Samples]
|
||||
- https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html[Spring Cloud Contract Documentation]
|
||||
- https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html/deprecated[Accurest Legacy Documentation]
|
||||
- https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html/#spring-cloud-contract-stub-runner[Spring Cloud Contract Stub Runner Documentation]
|
||||
- https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html/#stub-runner-for-messaging[Spring Cloud Contract Stub Runner Messaging Documentation]
|
||||
- https://gitter.im/spring-cloud/spring-cloud-contract[Spring Cloud Contract Gitter]
|
||||
- https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract-maven-plugin/[Spring Cloud Contract Maven Plugin]
|
||||
- https://www.youtube.com/watch?v=sAAklvxmPmk[Spring Cloud Contract WJUG Presentation by Marcin Grzejszczak]
|
||||
Unresolved directive in README.adoc - include::verifier_links.adoc[]
|
||||
|
||||
=== Spring Cloud Contract WireMock
|
||||
|
||||
@@ -1389,18 +826,13 @@ Here you can find interesting links related to Spring Cloud Contract Verifier:
|
||||
:doc_samples: {core_path}/samples/wiremock-jetty
|
||||
:wiremock_tests: {core_path}/spring-cloud-contract-wiremock
|
||||
|
||||
== Spring Cloud Contract WireMock
|
||||
|
||||
Modules giving you the possibility to use
|
||||
http://wiremock.org[WireMock] with different servers by using the
|
||||
"ambient" server embedded in a Spring Boot application. Check out the
|
||||
http://wiremock.org[WireMock] in a Spring Boot application. Check out the
|
||||
https://github.com/spring-cloud/spring-cloud-contract/tree/{branch}/samples[samples]
|
||||
for more details.
|
||||
|
||||
IMPORTANT: The Spring Cloud Release Train BOM imports `spring-cloud-contract-dependencies`
|
||||
which in turn has exclusions for the dependencies needed by WireMock. This might lead to a situation that
|
||||
even if you're not using Spring Cloud Contract then your dependencies will be influenced
|
||||
anyways.
|
||||
|
||||
If you have a Spring Boot application that uses Tomcat as an embedded
|
||||
server, for example (the default with `spring-boot-starter-web`), then
|
||||
you can simply add `spring-cloud-contract-wiremock` to your classpath
|
||||
@@ -1519,7 +951,7 @@ public class WiremockForDocsClassRuleTests {
|
||||
|
||||
The use `@ClassRule` means that the server will shut down after all the methods in this class.
|
||||
|
||||
== Relaxed SSL Validation for Rest Template
|
||||
=== Relaxed SSL Validation for Rest Template
|
||||
|
||||
WireMock allows you to stub a "secure" server with an "https" URL protocol. If your application wants to
|
||||
contact that stub server in an integration test, then it will find that the SSL certificates are not
|
||||
@@ -1562,7 +994,7 @@ be selected by the `RestTemplateBuilder` and configured to ignore SSL errors. If
|
||||
client you don't need the annotation (but it won't do any harm). There is no support currently for other clients, but
|
||||
it may be added in future releases.
|
||||
|
||||
== WireMock and Spring MVC Mocks
|
||||
=== WireMock and Spring MVC Mocks
|
||||
|
||||
Spring Cloud Contract provides a convenience class that can load JSON WireMock stubs into a
|
||||
Spring `MockRestServiceServer`. Here's an example:
|
||||
@@ -1609,7 +1041,7 @@ particular version of Jetty (currently 9.2). To use the native Jetty
|
||||
you need to add the native wiremock dependencies and exclude the
|
||||
Spring Boot container if there is one.
|
||||
|
||||
== Generating Stubs using RestDocs
|
||||
=== Generating Stubs using RestDocs
|
||||
|
||||
https://projects.spring.io/spring-restdocs[Spring RestDocs] can be
|
||||
used to generate documentation (e.g. in asciidoctor format) for an
|
||||
@@ -1739,7 +1171,7 @@ After that, you can create a stub using WireMock in a
|
||||
number of different ways, including as described above using
|
||||
`@AutoConfigureWireMock(stubs="classpath:resource.json")`.
|
||||
|
||||
== Generating Contracts using RestDocs
|
||||
=== Generating Contracts using RestDocs
|
||||
|
||||
Another thing that can be generated with Spring RestDocs is the Spring Cloud
|
||||
Contract DSL file and documentation. If you combine that with Spring Cloud
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
=== Links
|
||||
== Links
|
||||
|
||||
Here you can find interesting links related to Spring Cloud Contract Verifier:
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
:doc_samples: {core_path}/samples/wiremock-jetty
|
||||
:wiremock_tests: {core_path}/spring-cloud-contract-wiremock
|
||||
|
||||
== Migrations
|
||||
|
||||
In the following document we will write about necessary migration steps between versions.
|
||||
|
||||
=== 1.0.x -> 1.1.x
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
include::verifier_introduction.adoc[]
|
||||
|
||||
include::verifier_rest.adoc[]
|
||||
include::verifier_setup.adoc[]
|
||||
|
||||
include::verifier_messaging.adoc[]
|
||||
|
||||
@@ -23,6 +23,4 @@ include::verifier_stubrunner.adoc[]
|
||||
|
||||
include::verifier_stubrunner_msg.adoc[]
|
||||
|
||||
include::verifier_contract.adoc[]
|
||||
|
||||
include::verifier_links.adoc[]
|
||||
include::verifier_contract.adoc[]
|
||||
@@ -21,14 +21,10 @@ This project provides support for Consumer Driven Contracts and service schemas
|
||||
range of options for writing tests, publishing them as assets, asserting that a contract is kept by producers
|
||||
and consumers, for HTTP and message-based interactions.
|
||||
|
||||
== Spring Cloud Contract Verifier
|
||||
|
||||
include::spring-cloud-contract-verifier.adoc[]
|
||||
|
||||
== Spring Cloud Contract WireMock
|
||||
|
||||
include::spring-cloud-wiremock.adoc[]
|
||||
|
||||
== Migrations
|
||||
include::migrations.adoc[]
|
||||
|
||||
include::migrations.adoc[]
|
||||
include::links.adoc[]
|
||||
@@ -2,6 +2,7 @@
|
||||
:doc_samples: {core_path}/samples/wiremock-jetty
|
||||
:wiremock_tests: {core_path}/spring-cloud-contract-wiremock
|
||||
|
||||
== Spring Cloud Contract WireMock
|
||||
|
||||
Modules giving you the possibility to use
|
||||
http://wiremock.org[WireMock] in a Spring Boot application. Check out the
|
||||
@@ -88,7 +89,7 @@ include::{doc_samples}/src/test/java/com/example/WiremockForDocsClassRuleTests.j
|
||||
|
||||
The use `@ClassRule` means that the server will shut down after all the methods in this class.
|
||||
|
||||
== Relaxed SSL Validation for Rest Template
|
||||
=== Relaxed SSL Validation for Rest Template
|
||||
|
||||
WireMock allows you to stub a "secure" server with an "https" URL protocol. If your application wants to
|
||||
contact that stub server in an integration test, then it will find that the SSL certificates are not
|
||||
@@ -131,7 +132,7 @@ be selected by the `RestTemplateBuilder` and configured to ignore SSL errors. If
|
||||
client you don't need the annotation (but it won't do any harm). There is no support currently for other clients, but
|
||||
it may be added in future releases.
|
||||
|
||||
== WireMock and Spring MVC Mocks
|
||||
=== WireMock and Spring MVC Mocks
|
||||
|
||||
Spring Cloud Contract provides a convenience class that can load JSON WireMock stubs into a
|
||||
Spring `MockRestServiceServer`. Here's an example:
|
||||
@@ -158,7 +159,7 @@ particular version of Jetty (currently 9.2). To use the native Jetty
|
||||
you need to add the native wiremock dependencies and exclude the
|
||||
Spring Boot container if there is one.
|
||||
|
||||
== Generating Stubs using RestDocs
|
||||
=== Generating Stubs using RestDocs
|
||||
|
||||
https://projects.spring.io/spring-restdocs[Spring RestDocs] can be
|
||||
used to generate documentation (e.g. in asciidoctor format) for an
|
||||
@@ -288,7 +289,7 @@ After that, you can create a stub using WireMock in a
|
||||
number of different ways, including as described above using
|
||||
`@AutoConfigureWireMock(stubs="classpath:resource.json")`.
|
||||
|
||||
== Generating Contracts using RestDocs
|
||||
=== Generating Contracts using RestDocs
|
||||
|
||||
Another thing that can be generated with Spring RestDocs is the Spring Cloud
|
||||
Contract DSL file and documentation. If you combine that with Spring Cloud
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
=== Contract DSL
|
||||
== Contract DSL
|
||||
|
||||
IMPORTANT: Remember that inside the contract file you have to provide the fully qualified name to
|
||||
the `Contract` class and the `make` static import i.e. `org.springframework.cloud.spec.Contract.make { ... }`.
|
||||
@@ -24,7 +24,7 @@ Not all features of the DSL are used in example above. If you didn't find what y
|
||||
|
||||
> You can easily compile Contracts to WireMock stubs mapping using standalone maven command: `mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:convert`.
|
||||
|
||||
==== Limitations
|
||||
=== Limitations
|
||||
|
||||
WARNING: Spring Cloud Contract Verifier doesn't support XML properly. Please use JSON or help us implement this feature.
|
||||
|
||||
@@ -36,9 +36,9 @@ WARNING: Due to the fact that JSON structure can have any form it's sometimes im
|
||||
the `value(consumer(...), producer(...))` notation when using that in GString. That's why we highly recommend using the
|
||||
Groovy Map notation.
|
||||
|
||||
==== Common Top-Level elements
|
||||
=== Common Top-Level elements
|
||||
|
||||
===== Description
|
||||
==== Description
|
||||
|
||||
You can add a `description` to your contract that is nothing else but an arbitrary text. Example:
|
||||
|
||||
@@ -47,7 +47,7 @@ You can add a `description` to your contract that is nothing else but an arbitra
|
||||
include::{contract_spec_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=description,indent=0]
|
||||
----
|
||||
|
||||
===== Name
|
||||
==== Name
|
||||
|
||||
You can provide a name of your contract. Let's assume that you've provided a name `should register a user`.
|
||||
If you do this then the name of the autogenerated test will be equal to `validate_should_register_a_user`.
|
||||
@@ -57,7 +57,7 @@ IMPORTANT: Please ensure that the name doesn't contain any characters that will
|
||||
not possible to compile. Also remember that if you provide the same name for multiple contracts then your
|
||||
autogenerated tests will fail to compile and your generated stubs will override each other.
|
||||
|
||||
===== Ignoring contracts
|
||||
==== Ignoring contracts
|
||||
|
||||
If you want to ignore a contract you can either set a value of ignored contracts in the plugin configuration
|
||||
or just set the `ignored` property on the contract itself:
|
||||
@@ -67,7 +67,7 @@ or just set the `ignored` property on the contract itself:
|
||||
include::{contract_spec_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=ignored,indent=0]
|
||||
----
|
||||
|
||||
===== Passing values from files
|
||||
==== Passing values from files
|
||||
|
||||
Starting with version `1.2.0` it's possible to pass values from files. Let's assume that we have
|
||||
the following resources in our project.
|
||||
@@ -118,7 +118,7 @@ Following methods can be called in the top-level closure of a contract definitio
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=http_dsl,indent=0]
|
||||
----
|
||||
|
||||
==== Request
|
||||
=== Request
|
||||
|
||||
HTTP protocol requires only **method and address** to be specified in a request. The same information is mandatory in request definition of the Contract.
|
||||
|
||||
@@ -196,7 +196,7 @@ The WireMock stub will look more or less like this:
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/WireMockGroovyDslSpec.groovy[tags=multipartwiremock,indent=0]
|
||||
----
|
||||
|
||||
==== Response
|
||||
=== Response
|
||||
|
||||
Minimal response must contain **HTTP status code**.
|
||||
|
||||
@@ -207,14 +207,14 @@ include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract
|
||||
|
||||
Besides status response may contain **headers** and **body**, which are specified the same way as in the request (see previous paragraph).
|
||||
|
||||
==== Dynamic properties
|
||||
=== Dynamic properties
|
||||
|
||||
The contract can contain some dynamic properties - timestamps / ids etc. You don't want to enforce the consumers to stub their
|
||||
clocks to always return the same value of time so that it gets matched by the stub. That's why we allow you to provide the dynamic
|
||||
parts in your contracts in two ways. One is to pass them directly in the
|
||||
body and one to set them in a separate section called `testMatchers` and `stubMatchers`.
|
||||
|
||||
===== Dynamic properties inside the body
|
||||
==== Dynamic properties inside the body
|
||||
|
||||
You can set the properties inside the body either via the `value` method
|
||||
|
||||
@@ -239,7 +239,7 @@ $(client(...), server(...))
|
||||
All of the aforementioned approaches are equal. That means that `stub` and `client` methods are aliases over the `consumer`
|
||||
method. Let's take a closer look at what we can do with those values in the subsequent sections.
|
||||
|
||||
====== Regular expressions
|
||||
==== Regular expressions
|
||||
|
||||
You can use regular expressions to write your requests in Contract DSL. It is particularly useful when you want to indicate that a given response
|
||||
should be provided for requests that follow a given pattern. Also, you can use it when you need to use patterns and not exact values both
|
||||
@@ -276,7 +276,7 @@ so in your contract you can use it like this
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy[tags=contract_with_regex,indent=0]
|
||||
----
|
||||
|
||||
====== Passing optional parameters
|
||||
==== Passing optional parameters
|
||||
|
||||
It is possible to provide optional parameters in your contract. It's only possible to have optional parameter for the:
|
||||
|
||||
@@ -306,7 +306,7 @@ and the following stub:
|
||||
include::{plugins_path}/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy[tags=wiremock,indent=0]
|
||||
----
|
||||
|
||||
====== Executing custom methods on server side
|
||||
==== Executing custom methods on server side
|
||||
|
||||
It is also possible to define a method call to be executed on the server side during the test. Such a method can be added to the class defined as "baseClassForTests"
|
||||
in the configuration. Example:
|
||||
@@ -369,7 +369,7 @@ It would more or less like this:
|
||||
assertThat(response.statusCode()).isEqualTo(200);
|
||||
----
|
||||
|
||||
===== Referencing request from response
|
||||
==== Referencing request from response
|
||||
|
||||
The best situation is to provide fixed values but sometimes you need to reference a request in your response.
|
||||
In order to do this you can profit from the `fromRequest()` method that allows you to reference a bunch
|
||||
@@ -483,7 +483,7 @@ proper values. Additionally we're registering 2 helper functions. `escapejsonbod
|
||||
body in a format that can be embedded in a JSON. Another is `jsonpath` that for a given parameter knows how to
|
||||
find an object in the request body.
|
||||
|
||||
===== Dynamic properties in matchers sections
|
||||
==== Dynamic properties in matchers sections
|
||||
|
||||
If you've been working with https://docs.pact.io/[Pact] this might seem familiar. Quite a few users
|
||||
are used to having a separation between the body and setting dynamic parts of your contract.
|
||||
@@ -671,7 +671,7 @@ As you can see the assertion is malformed. That's because only the first element
|
||||
In order to fix this it's best to apply the assertion to the whole `$.events` collection and assert it
|
||||
via the `byCommand(...)` method.
|
||||
|
||||
==== JAX-RS support
|
||||
=== JAX-RS support
|
||||
|
||||
We support JAX-RS 2 Client API. Base class needs to define `protected WebTarget webTarget` and server initialization, right now the only option how to test JAX-RS API is to start a web server.
|
||||
|
||||
@@ -681,7 +681,7 @@ In order to use JAX-RS mode, use the following settings:
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
testMode === 'JAXRSCLIENT'
|
||||
testMode == 'JAXRSCLIENT'
|
||||
----
|
||||
|
||||
Example of a test API generated:
|
||||
@@ -691,7 +691,7 @@ Example of a test API generated:
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientMethodBuilderSpec.groovy[tags=jaxrs,indent=0]
|
||||
----
|
||||
|
||||
==== Async support
|
||||
=== Async support
|
||||
|
||||
If you're using asynchronous communication on the server side (your controllers are returning
|
||||
`Callable`, `DeferredResult` etc. then inside your contract you have to provide in the `response`
|
||||
@@ -712,7 +712,7 @@ org.springframework.cloud.contract.spec.Contract.make {
|
||||
}
|
||||
----
|
||||
|
||||
==== Working with Context Paths
|
||||
=== Working with Context Paths
|
||||
|
||||
Spring Cloud Contract supports context paths.
|
||||
|
||||
@@ -766,11 +766,11 @@ That way all:
|
||||
- your contracts reflect that you have a context path, thus your generated stubs will also
|
||||
have that information (e.g. in the stubs you'll see that you have too call `/my-context-path/url`)
|
||||
|
||||
==== Messaging Top-Level Elements
|
||||
=== Messaging Top-Level Elements
|
||||
|
||||
The DSL for messaging looks a little bit different than the one that focuses on HTTP.
|
||||
|
||||
===== Output triggered by a method
|
||||
==== Output triggered by a method
|
||||
|
||||
The output message can be triggered by calling a method (e.g. a Scheduler was started and a message was sent)
|
||||
|
||||
@@ -782,7 +782,7 @@ include::{tests_path}/samples-messaging-integration/src/test/groovy/com/example/
|
||||
In this case the output message will be sent to `output` if a method called `bookReturnedTriggered` will be executed. In the message *publisher's* side
|
||||
we will generate a test that will call that method to trigger the message. On the *consumer* side you can use the `some_label` to trigger the message.
|
||||
|
||||
===== Output triggered by a message
|
||||
==== Output triggered by a message
|
||||
|
||||
The output message can be triggered by receiving a message.
|
||||
|
||||
@@ -795,7 +795,7 @@ In this case the output message will be sent to `output` if a proper message wil
|
||||
we will generate a test that will send the input message to the defined destination. On the *consumer* side you can either send a message to the input
|
||||
destination or use the `some_label` to trigger the message.
|
||||
|
||||
===== Consumer / Producer
|
||||
==== Consumer / Producer
|
||||
|
||||
In HTTP you have a notion of `client`/`stub and `server`/`test` notation. You can use them also in messaging but we're providing also the `consumer` and `produer` methods
|
||||
as presented below (note you can use either `$` or `value` methods to provide `consumer` and `producer` parts)
|
||||
@@ -805,7 +805,7 @@ as presented below (note you can use either `$` or `value` methods to provide `c
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=consumer_producer]
|
||||
----
|
||||
|
||||
==== Multiple contracts in one file
|
||||
=== Multiple contracts in one file
|
||||
|
||||
It's possible to define multiple contracts in one file. An example of such a contract can look like this
|
||||
|
||||
@@ -884,9 +884,9 @@ TIP: As you can see it's much better if you name your contracts since then your
|
||||
are far more meaningful.
|
||||
|
||||
|
||||
=== Customization
|
||||
== Customization
|
||||
|
||||
==== Extending the DSL
|
||||
=== Extending the DSL
|
||||
|
||||
It is possible to provide your own functions to the DSL. The key requirement for this
|
||||
feature was to maintain the static compatibility. Below you will be able to see an example
|
||||
@@ -897,7 +897,7 @@ of:
|
||||
|
||||
The full example can be found https://github.com/spring-cloud-samples/spring-cloud-contract-samples[here].
|
||||
|
||||
===== Common JAR
|
||||
==== Common JAR
|
||||
|
||||
Below you can find three classes that we will reuse in the DSLs.
|
||||
|
||||
@@ -922,12 +922,12 @@ include::{samples_url}/common/src/main/java/com/example/ConsumerUtils.java[]
|
||||
include::{samples_url}/common/src/main/java/com/example/ProducerUtils.java[]
|
||||
----
|
||||
|
||||
===== Adding the dependency to project
|
||||
==== Adding the dependency to project
|
||||
|
||||
In order for the plugins and IDE to be able to reference the common JAR classes you need
|
||||
to pass the dependency to your project.
|
||||
|
||||
====== Test dependency in project's dependencies
|
||||
==== Test dependency in project's dependencies
|
||||
|
||||
First add the common jar dependency as a test dependency. That way since your
|
||||
contracts files are available at test resources path, automatically the
|
||||
@@ -945,7 +945,7 @@ include::{samples_url}/producer/pom.xml[tags=test_dep,indent=0]
|
||||
include::{samples_url}/producer/build.gradle[tags=test_dep,indent=0]
|
||||
----
|
||||
|
||||
====== Test dependency in plugin's dependencies
|
||||
==== Test dependency in plugin's dependencies
|
||||
|
||||
Now you have to add the dependency for the plugin to reuse at runtime.
|
||||
|
||||
@@ -961,7 +961,7 @@ include::{samples_url}/producer/pom.xml[tags=test_dep_in_plugin,indent=0]
|
||||
include::{samples_url}/producer/build.gradle[tags=test_dep_in_plugin,indent=0]
|
||||
----
|
||||
|
||||
====== Referencing classes in DSLs
|
||||
==== Referencing classes in DSLs
|
||||
|
||||
Now you can reference your classes in your DSL. Example:
|
||||
|
||||
@@ -970,7 +970,7 @@ Now you can reference your classes in your DSL. Example:
|
||||
include::{samples_url}/producer/src/test/resources/contracts/beer/rest/shouldGrantABeerIfOldEnough.groovy[indent=0]
|
||||
----
|
||||
|
||||
=== Pluggable architecture
|
||||
== Pluggable architecture
|
||||
|
||||
There are cases where you have your contracts defined in other formats
|
||||
like YAML, RAML or PACT. On the other hand you'd like to profit from
|
||||
@@ -979,7 +979,7 @@ of either of those. Also you can customize the way tests are generated (for exam
|
||||
tests for other languages) and you can do the same for stubs generation (you can generate
|
||||
stubs for other stub http server implementations).
|
||||
|
||||
==== Custom contract converter
|
||||
=== Custom contract converter
|
||||
|
||||
Let's assume that your contract is written in a YAML file like this:
|
||||
|
||||
@@ -1016,13 +1016,13 @@ and the YAML implementation
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy[indent=0,lines=16..-1]
|
||||
----
|
||||
|
||||
===== Pact converter
|
||||
==== Pact converter
|
||||
|
||||
Spring Cloud Contract comes with an out of the box support for https://docs.pact.io/[Pact] representation of contracts.
|
||||
In other words instead of using the Groovy DSL you can use Pact files. In this section
|
||||
we will present how to add such a support for your project.
|
||||
|
||||
====== Pact contract
|
||||
==== Pact contract
|
||||
|
||||
We will be working on the following example of a Pact contract. We've placed this file under
|
||||
the `src/test/resources/contracts` folder.
|
||||
@@ -1032,7 +1032,7 @@ the `src/test/resources/contracts` folder.
|
||||
include::{standalone_pact_path}/pact-http-server/src/test/resources/contracts/fraud/shouldMarkClientAsFraud.json[indent=0]
|
||||
----
|
||||
|
||||
====== Pact for producers
|
||||
==== Pact for producers
|
||||
|
||||
On the producer side you have add to your plugin configuration two additional dependencies.
|
||||
One is the Spring Cloud Contract Pact support and the other represents the current
|
||||
@@ -1106,7 +1106,7 @@ and the stub looking like this
|
||||
}
|
||||
----
|
||||
|
||||
====== Pact for consumers
|
||||
==== Pact for consumers
|
||||
|
||||
On the producer side you have add to your project dependencies two additional dependencies.
|
||||
One is the Spring Cloud Contract Pact support and the other represents the current
|
||||
@@ -1124,7 +1124,7 @@ include::{standalone_pact_path}/pact-http-client/pom.xml[tags=pact_dependency,in
|
||||
include::{standalone_pact_path}/pact-http-client/build.gradle[tags=pact_dependency,indent=0]
|
||||
----
|
||||
|
||||
==== Custom test generator
|
||||
=== Custom test generator
|
||||
|
||||
If you want to generate tests for different languages than Java or you're
|
||||
not happy with the way we're building Java tests for you then you can register
|
||||
@@ -1146,7 +1146,7 @@ org.springframework.cloud.contract.verifier.builder.SingleTestGenerator=/
|
||||
com.example.MyGenerator
|
||||
----
|
||||
|
||||
==== Custom stub generator
|
||||
=== Custom stub generator
|
||||
|
||||
If you want to generate stubs for other stub server than WireMock it's enough to
|
||||
plug in your own implementation of this interface:
|
||||
@@ -1169,7 +1169,7 @@ The default implementation is the WireMock stub generation.
|
||||
TIP: You can provide multiple stub generator implementations. That way for example from a single
|
||||
DSL as input you can e.g. produce WireMock stubs and Pact files too!
|
||||
|
||||
==== Custom Stub Runner
|
||||
=== Custom Stub Runner
|
||||
|
||||
If you decide to have a custom stub generation you also need a custom way of running
|
||||
stubs with your different stub provider.
|
||||
@@ -1198,7 +1198,7 @@ that way you'll be able to run stubs using Moco.
|
||||
IMPORTANT: If you don't provide any implementation then the default one - WireMock based
|
||||
will be picked. If you provide more than one then the first one on the list will be picked.
|
||||
|
||||
==== Custom Stub Downloader
|
||||
=== Custom Stub Downloader
|
||||
|
||||
You can customize the way your stubs are downloaded. It's enough to create an
|
||||
implementation of the `StubDownloaderBuilder`
|
||||
|
||||
373
docs/src/main/asciidoc/verifier_faq.adoc
Normal file
373
docs/src/main/asciidoc/verifier_faq.adoc
Normal file
@@ -0,0 +1,373 @@
|
||||
:introduction_url: https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/master
|
||||
|
||||
== Spring Cloud Contract FAQ
|
||||
|
||||
=== Why use Spring Cloud Contract Verifier and not X ?
|
||||
|
||||
For the time being Spring Cloud Contract Verifier is a JVM based tool. So it could be your first pick when you're already creating
|
||||
software for the JVM. This project has a lot of really interesting features but especially quite a few of them definitely make
|
||||
Spring Cloud Contract Verifier stand out on the "market" of Consumer Driven Contract (CDC) tooling. Out of many the most interesting are:
|
||||
|
||||
- Possibility to do CDC with messaging
|
||||
- Clear and easy to use, statically typed DSL
|
||||
- Possibility to copy paste your current JSON file to the contract and only edit its elements
|
||||
- Automatic generation of tests from the defined Contract
|
||||
- Stub Runner functionality - the stubs are automatically downloaded at runtime from Nexus / Artifactory
|
||||
- Spring Cloud integration - no discovery service is needed for integration tests
|
||||
|
||||
=== What is this value(consumer(), producer()) ?
|
||||
|
||||
One of the biggest challenges related to stubs is their reusability. Only if they can be vastly used, will they serve their purpose.
|
||||
What typically makes that difficult are the hard-coded values of request / response elements. For example dates or ids.
|
||||
Imagine the following JSON request
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "2016-10-10 20:10:15",
|
||||
"id" : "9febab1c-6f36-4a0b-88d6-3b6a6d81cd4a",
|
||||
"body" : "foo"
|
||||
}
|
||||
----
|
||||
|
||||
and JSON response
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "2016-10-10 21:10:15",
|
||||
"id" : "c4231e1f-3ca9-48d3-b7e7-567d55f0d051",
|
||||
"body" : "bar"
|
||||
}
|
||||
----
|
||||
|
||||
Imagine the pain required to set proper value of the `time` field (let's assume that this content is generated by the
|
||||
database) by changing the clock in the system or providing stub implementations of data providers. The same is related
|
||||
to the field called `id`. Will you create a stubbed implementation of UUID generator? Makes little sense...
|
||||
|
||||
So as a consumer you would like to send a request that matches any form of a time or any UUID. That way your system
|
||||
will work as usual - will generate data and you won't have to stub anything out. Let's assume that in case of the aforementioned
|
||||
JSON the most important part is the `body` field. You can focus on that and provide matching for other fields. In other words
|
||||
you would like the stub to work like this:
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "SOMETHING THAT MATCHES TIME",
|
||||
"id" : "SOMETHING THAT MATCHES UUID",
|
||||
"body" : "foo"
|
||||
}
|
||||
----
|
||||
|
||||
As far as the response goes as a consumer you need a concrete value that you can operate on. So such a JSON is valid
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "2016-10-10 21:10:15",
|
||||
"id" : "c4231e1f-3ca9-48d3-b7e7-567d55f0d051",
|
||||
"body" : "bar"
|
||||
}
|
||||
----
|
||||
|
||||
As you could see in the previous sections we generate tests from contracts. So from the producer's side the situation looks
|
||||
much different. We're parsing the provided contract and in the test we want to send a real request to your endpoints.
|
||||
So for the case of a producer for the request we can't have any sort of matching. We need concrete values that the
|
||||
producer's backend can work on. Such a JSON would be a valid one:
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "2016-10-10 20:10:15",
|
||||
"id" : "9febab1c-6f36-4a0b-88d6-3b6a6d81cd4a",
|
||||
"body" : "foo"
|
||||
}
|
||||
----
|
||||
|
||||
On the other hand from the point of view of the validity of the contract the response doesn't necessarily have to
|
||||
contain concrete values of `time` or `id`. Let's say that you generate those on the producer side - again, you'd
|
||||
have to do a lot of stubbing to ensure that you always return the same values. That's why from the producer's side
|
||||
what you might want is the following response:
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "SOMETHING THAT MATCHES TIME",
|
||||
"id" : "SOMETHING THAT MATCHES UUID",
|
||||
"body" : "bar"
|
||||
}
|
||||
----
|
||||
|
||||
How can you then provide one time a matcher for the consumer and a concrete value for the producer and vice versa?
|
||||
In Spring Cloud Contract we're allowing you to provide a *dynamic value*. That means that it can differ for both
|
||||
sides of the communication. You can pass the values:
|
||||
|
||||
Either via the `value` method
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
value(consumer(...), producer(...))
|
||||
value(stub(...), test(...))
|
||||
value(client(...), server(...))
|
||||
----
|
||||
|
||||
or using the `$()` method
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
$(consumer(...), producer(...))
|
||||
$(stub(...), test(...))
|
||||
$(client(...), server(...))
|
||||
----
|
||||
|
||||
You can read more about this in the https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html#_contract_dsl[Contract DSL section].
|
||||
|
||||
Calling `value()` or `$()` tells Spring Cloud Contract that you will be passing a dynamic value.
|
||||
Inside the `consumer()` method you pass the value that should be used on the consumer side (in the generated stub).
|
||||
Inside the `producer()` method you pass the value that should be used on the producer side (in the generated test).
|
||||
|
||||
TIP: If on one side you have passed the regular expression and you haven't passed the other, then the
|
||||
other side will get auto-generated.
|
||||
|
||||
Most often you will use that method together with the `regex` helper method. E.g. `consumer(regex('[0-9]{10}'))`.
|
||||
|
||||
To sum it up the contract for the aforementioned scenario would look more or less like this (the regular expression
|
||||
for time and UUID are simplified and most likely invalid but we want to keep things very simple in this example):
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
org.springframework.cloud.contract.spec.Contract.make {
|
||||
request {
|
||||
method 'GET'
|
||||
url '/someUrl'
|
||||
body([
|
||||
time : value(consumer(regex('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-2][0-9]-[0-5][0-9]-[0-5][0-9]')),
|
||||
id: value(consumer(regex('[0-9a-zA-z]{8}-[0-9a-zA-z]{4}-[0-9a-zA-z]{4}-[0-9a-zA-z]{12}'))
|
||||
body: "foo"
|
||||
])
|
||||
}
|
||||
response {
|
||||
status 200
|
||||
body([
|
||||
time : value(producer(regex('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-2][0-9]-[0-5][0-9]-[0-5][0-9]')),
|
||||
id: value([producer(regex('[0-9a-zA-z]{8}-[0-9a-zA-z]{4}-[0-9a-zA-z]{4}-[0-9a-zA-z]{12}'))
|
||||
body: "bar"
|
||||
])
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
IMPORTANT: Please read the http://groovy-lang.org/json.html[Groovy docs related to JSON] to understand how to
|
||||
properly structure the request / response bodies.
|
||||
|
||||
=== How to do Stubs versioning?
|
||||
|
||||
==== API Versioning
|
||||
|
||||
Let's try to answer a question what versioning really means. If you're referring to the API version then there are
|
||||
different approaches.
|
||||
|
||||
- use Hypermedia, links and do not version your API by any means
|
||||
- pass versions through headers / urls
|
||||
|
||||
I will not try to answer a question which approach is better. Whatever suit your needs and allows you to generate
|
||||
business value should be picked.
|
||||
|
||||
Let's assume that you do version your API. In that case you should provide as many contracts as many versions you support.
|
||||
You can create a subfolder for every version or append it to th contract name - whatever suits you more.
|
||||
|
||||
==== JAR versioning
|
||||
|
||||
If by versioning you mean the version of the JAR that contains the stubs then there are essentially two main approaches.
|
||||
|
||||
Let's assume that you're doing Continuous Delivery / Deployment which means that you're generating a new version of
|
||||
the jar each time you go through the pipeline and that jar can go to production at any time. For example your jar version
|
||||
looks like this (it got built on the 20.10.2016 at 20:15:21) :
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
1.0.0.20161020-201521-RELEASE
|
||||
----
|
||||
|
||||
In that case your generated stub jar will look like this.
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
1.0.0.20161020-201521-RELEASE-stubs.jar
|
||||
----
|
||||
|
||||
In this case you should inside your `application.yml` or `@AutoConfigureStubRunner` when referencing stubs provide the
|
||||
latest version of the stubs. You can do that by passing the `+` sign. Example
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:8080"})
|
||||
----
|
||||
|
||||
If the versioning however is fixed (e.g. `1.0.4.RELEASE` or `2.1.1`) then you have to set the concrete value of the jar
|
||||
version. Example for 2.1.1.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:2.1.1:stubs:8080"})
|
||||
----
|
||||
|
||||
==== Dev or prod stubs
|
||||
|
||||
You can manipulate the classifier to run the tests against current development version of the stubs of other services
|
||||
or the ones that were deployed to production. If you alter your build to deploy the stubs with the `prod-stubs` classifier
|
||||
once you reach production deployment then you can run tests in one case with dev stubs and one with prod stubs.
|
||||
|
||||
Example of tests using development version of stubs
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:8080"})
|
||||
----
|
||||
|
||||
Example of tests using production version of stubs
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:prod-stubs:8080"})
|
||||
----
|
||||
|
||||
You can pass those values also via properties from your deployment pipeline.
|
||||
|
||||
=== Common repo with contracts
|
||||
|
||||
Another way of storing contracts other than having them with the producer is keeping them in a common place.
|
||||
It can be related to security issues where the consumers can't clone the producer's code. Also if you keep
|
||||
contracts in a single place then you, as a producer, will know how many consumers you have and which
|
||||
consumer will you break with your local changes.
|
||||
|
||||
==== Repo structure
|
||||
|
||||
Let's assume that we have a producer with coordinates `com.example:server` and 3 consumers: `client1`,
|
||||
`client2`, `client3`. Then in the repository with common contracts you would have the following setup
|
||||
(which you can checkout https://github.com/spring-cloud/spring-cloud-contract/tree/1.0.x/samples/standalone/contracts[here]:
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
├── com
|
||||
│ └── example
|
||||
│ └── server
|
||||
│ ├── client1
|
||||
│ │ └── expectation.groovy
|
||||
│ ├── client2
|
||||
│ │ └── expectation.groovy
|
||||
│ ├── client3
|
||||
│ │ └── expectation.groovy
|
||||
│ └── pom.xml
|
||||
├── mvnw
|
||||
├── mvnw.cmd
|
||||
├── pom.xml
|
||||
└── src
|
||||
└── assembly
|
||||
└── contracts.xml
|
||||
----
|
||||
|
||||
As you can see the under the slash-delimited groupid `/` artifact id folder (`com/example/server`) you have
|
||||
expectations of the 3 consumers (`client1`, `client2` and `client3`). Expectations are the standard Groovy DSL
|
||||
contract files as described throughout this documentation. This repository has to produce a JAR file that maps
|
||||
one to one to the contents of the repo.
|
||||
|
||||
Example of a `pom.xml` inside the `server` folder.
|
||||
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{introduction_url}/samples/standalone/contracts/com/example/server/pom.xml[indent=0]
|
||||
----
|
||||
|
||||
As you can see there are no dependencies other than the Spring Cloud Contract Maven Plugin.
|
||||
Those poms are necessary for the consumer side to run `mvn clean install -DskipTests` to locally install
|
||||
stubs of the producer project.
|
||||
|
||||
The `pom.xml` in the root folder can look like this:
|
||||
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{introduction_url}/samples/standalone/contracts/pom.xml[indent=0]
|
||||
----
|
||||
|
||||
It's using the assembly plugin in order to build the JAR with all the contracts. Example of such setup is here:
|
||||
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{introduction_url}/samples/standalone/contracts/src/assembly/contracts.xml[indent=0]
|
||||
----
|
||||
|
||||
==== Workflow
|
||||
|
||||
The workflow would look similar to the one presented in the `Step by step guide to CDC`. The only difference
|
||||
is that the producer doesn't own the contracts anymore. So the consumer and the producer have to work on
|
||||
common contracts in a common repository.
|
||||
|
||||
==== Consumer
|
||||
|
||||
When the *consumer* wants to work on the contracts offline, instead of cloning the producer code, the
|
||||
consumer team clones the common repository, goes to the required producer's folder (e.g. `com/example/server`)
|
||||
and runs `mvn clean install -DskipTests` to install locally the stubs converted from the contracts.
|
||||
|
||||
TIP: You need to have http://maven.apache.org/download.cgi[Maven installed locally]
|
||||
|
||||
==== Producer
|
||||
|
||||
As a *producer* it's enough to alter the Spring Cloud Contract Verifier to provide the URL and the dependency
|
||||
of the JAR containing the contracts:
|
||||
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{introduction_url}/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-remote-contracts/pom-with-repo.xml[tags=remote_config,indent=0]
|
||||
----
|
||||
|
||||
With this setup the JAR with groupid `com.example.standalone` and artifactid `contracts` will be downloaded
|
||||
from `http://link/to/your/nexus/or/artifactory/or/sth`. It will be then unpacked in a local temporary folder
|
||||
and contracts present under the `com/example/server` will be picked as the ones used to generate the
|
||||
tests and the stubs. Due to this convention the producer team will know which consumer teams will be broken
|
||||
when some incompatible changes are done.
|
||||
|
||||
The rest of the flow looks the same.
|
||||
|
||||
=== Can I have multiple base classes for tests?
|
||||
|
||||
Yes! Check out the https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html#_different_base_classes_for_contracts[Different base classes for contracts] sections
|
||||
of either Gradle or Maven plugins.
|
||||
|
||||
=== How can I debug the request/response being sent by the generated tests client?
|
||||
|
||||
The generated tests all boil down to RestAssured in some form or fashion which relies on https://hc.apache.org/httpcomponents-client-ga/[Apache HttpClient]. HttpClient has a facility called https://hc.apache.org/httpcomponents-client-ga/logging.html#Wire_Logging[wire logging] which logs the entire request and response to HttpClient. Spring Boot has a logging https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html[common application property] for doing this sort of thing, just add this to your application properties
|
||||
[source,properties,indent=0]
|
||||
----
|
||||
logging.level.org.apache.http.wire=DEBUG
|
||||
----
|
||||
|
||||
==== How can I debug the mapping/request/response being sent by WireMock?
|
||||
|
||||
Starting from version `1.2.0` we turn on WireMock logging to
|
||||
info and the WireMock notifier to being verbose. Now you will
|
||||
exactly know what request was received by WireMock server and which
|
||||
matching response definition was picked.
|
||||
|
||||
To turn off this feature just bump WireMock logging to `ERROR`
|
||||
|
||||
[source,properties,indent=0]
|
||||
----
|
||||
logging.level.com.github.tomakehurst.wiremock=ERROR
|
||||
----
|
||||
|
||||
==== How can I see what got registered in the HTTP server stub?
|
||||
|
||||
You can use the `mappingsOutputFolder` property on `@AutoConfigureStubRunner` or `StubRunnerRule`
|
||||
to dump all mappings per artifact id. Also the port at which the given stub server was
|
||||
started will be attached.
|
||||
|
||||
==== Can I reference the request from the response?
|
||||
|
||||
Yes! With version 1.1.0 we've added such a possibility. On the HTTP stub server side we're providing support
|
||||
for this for WireMock. In case of other HTTP server stubs you'll have to implement the approach yourself.
|
||||
|
||||
==== Can I reference text from file?
|
||||
|
||||
Yes! With version 1.2.0 we've added such a possibility. It's enough to call `file(...)` method in the
|
||||
DSL and provide a path relative to where the contract lays.
|
||||
@@ -1,4 +1,4 @@
|
||||
=== Introduction
|
||||
== Spring Cloud Contract Verifier Introduction
|
||||
|
||||
TIP: The Accurest project was initially started by Marcin Grzejszczak and Jakub Kubrynski (http://codearte.io[codearte.io])
|
||||
|
||||
@@ -13,13 +13,13 @@ Full test is generated by Spring Cloud Contract Verifier.
|
||||
|
||||
Spring Cloud Contract Verifier moves TDD to the level of software architecture.
|
||||
|
||||
==== Why?
|
||||
=== Why?
|
||||
|
||||
Let us assume that we have a system comprising of multiple microservices:
|
||||
|
||||
image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/{branch}/docs/src/main/asciidoc/images/Deps.png[Microservices Architecture]
|
||||
|
||||
===== Testing issues
|
||||
==== Testing issues
|
||||
|
||||
If we wanted to test the application in top left corner if it can communicate with other services then we could do one of two things:
|
||||
|
||||
@@ -63,7 +63,7 @@ image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/{bra
|
||||
Spring Cloud Contract Verifier gives you the certainty that the stubs that you're using were created by the service that you're calling. Also if you can use them it means that they were
|
||||
tested against the producer's side. In other words - you can trust those stubs.
|
||||
|
||||
==== Purposes
|
||||
=== Purposes
|
||||
|
||||
The main purposes of Spring Cloud Contract Verifier with Stub Runner are:
|
||||
|
||||
@@ -77,9 +77,9 @@ Let's assume that we have a business use case of fraud check. If a user can be a
|
||||
we would assume that you would create 2 contracts. One for the positive and one for the negative fraud case.
|
||||
Contract tests are used to test contracts between applications and not to simulate full behaviour.
|
||||
|
||||
==== How
|
||||
=== How
|
||||
|
||||
===== Define the contract
|
||||
==== Define the contract
|
||||
|
||||
As consumers we need to define what exactly we want to achieve. We need to formulate our expectations. That's why we write the following contract.
|
||||
|
||||
@@ -90,7 +90,7 @@ Let’s assume that we’d like to send the request containing the id of the cli
|
||||
include::{introduction_url}/samples/standalone/dsl/http-server/src/test/resources/contracts/fraud/shouldMarkClientAsFraud.groovy[]
|
||||
----
|
||||
|
||||
===== Client Side
|
||||
==== Client Side
|
||||
|
||||
Spring Cloud Contract will generate stubs, which you can use during client side testing.
|
||||
You will have a WireMock instance / Messaging route up and running that simulates the service Y.
|
||||
@@ -112,7 +112,7 @@ include::{introduction_url}/samples/standalone/dsl/http-client/src/test/java/com
|
||||
|
||||
After that, during the tests Spring Cloud Contract will automatically find the stubs (simulating the real service) in Maven repository and expose them on configured (or random) port.
|
||||
|
||||
===== Server Side
|
||||
==== Server Side
|
||||
|
||||
Being a service Y since you are developing your stub, you need to be sure that it's actually resembling your
|
||||
concrete implementation. You can't have a situation where your stub acts in one way and your application on
|
||||
@@ -146,7 +146,7 @@ public void validate_shouldMarkClientAsFraud() throws Exception {
|
||||
}
|
||||
----
|
||||
|
||||
==== Step by step guide to CDC
|
||||
=== Step by step guide to CDC
|
||||
|
||||
Let's take an example of Fraud Detection and Loan Issuance process. The business scenario is such that we want to issue loans to people but don't want them to steal the money from us. The current implementation of our system grants loans to everybody.
|
||||
|
||||
@@ -163,7 +163,7 @@ The https://github.com/spring-cloud/spring-cloud-contract/tree/{branch}/samples/
|
||||
TIP: In this case the ownership of the contracts lays on the producer side. It means that physically
|
||||
all the contract are present in the producer's repository
|
||||
|
||||
===== Technical note
|
||||
==== Technical note
|
||||
|
||||
If using the *SNAPSHOT* / *Milestone* / *Release Candidate* versions please add the following section to your
|
||||
|
||||
@@ -179,7 +179,7 @@ include::{introduction_url}/samples/standalone/dsl/http-server/pom.xml[tags=repo
|
||||
include::{introduction_url}/samples/standalone/dsl/http-server/build.gradle[tags=deps_repos,indent=0]
|
||||
----
|
||||
|
||||
===== Consumer side (Loan Issuance)
|
||||
==== Consumer side (Loan Issuance)
|
||||
|
||||
As a developer of the Loan Issuance service (a consumer of the Fraud Detection server):
|
||||
|
||||
@@ -353,7 +353,7 @@ What we did until now is an iterative process. We can play around with the contr
|
||||
|
||||
Once we're satisfied with the results and the test passes publish a PR to the server side. Currently the consumer side work is done.
|
||||
|
||||
===== Producer side (Fraud Detection server)
|
||||
==== Producer side (Fraud Detection server)
|
||||
|
||||
As a developer of the Fraud Detection server (a server to the Loan Issuance service):
|
||||
|
||||
@@ -470,7 +470,7 @@ git push origin master
|
||||
|
||||
Then we assume that your CI would run sth like `./mvnw clean deploy` which would publish both the application and the stub artifcats.
|
||||
|
||||
===== Consumer side (Loan Issuance) final step
|
||||
==== Consumer side (Loan Issuance) final step
|
||||
|
||||
As a developer of the Loan Issuance service (a consumer of the Fraud Detection server):
|
||||
|
||||
@@ -495,403 +495,31 @@ include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/{b
|
||||
|
||||
And that's it!
|
||||
|
||||
==== Dependencies
|
||||
=== Dependencies
|
||||
|
||||
The best way to add the dependencies is to just use the proper `starter` dependency.
|
||||
|
||||
For `stub-runner` use `spring-cloud-starter-stub-runner` and when you're using a plugin just add
|
||||
`spring-cloud-starter-contract-verifier`.
|
||||
|
||||
==== Additional links
|
||||
=== Additional links
|
||||
|
||||
Below you can find some resources related to Spring Cloud Contract Verifier and Stub Runner. Note that some can be outdated since the Spring Cloud Contract Verifier project
|
||||
is under constant development.
|
||||
|
||||
===== Spring Cloud Contract video
|
||||
==== Spring Cloud Contract video
|
||||
|
||||
You can check out the video from the Warsaw JUG about Spring Cloud Contract:
|
||||
|
||||
video::sAAklvxmPmk[youtube,start=538,width=640,height=480]
|
||||
|
||||
===== Readings
|
||||
==== Readings
|
||||
|
||||
- http://www.slideshare.net/MarcinGrzejszczak/stick-to-the-rules-consumer-driven-contracts-201507-confitura[Slides from Marcin Grzejszczak's talk about Accurest]
|
||||
- http://toomuchcoding.com/blog/categories/accurest/[Accurest related articles from Marcin Grzejszczak's blog]
|
||||
- http://toomuchcoding.com/blog/categories/spring-cloud-contract/[Spring Cloud Contract related articles from Marcin Grzejszczak's blog]
|
||||
- http://groovy-lang.org/json.html[Groovy docs regarding JSON]
|
||||
|
||||
==== Samples
|
||||
=== Samples
|
||||
|
||||
Here you can find some https://github.com/spring-cloud-samples/spring-cloud-contract-samples[samples].
|
||||
|
||||
=== FAQ
|
||||
|
||||
==== Why use Spring Cloud Contract Verifier and not X ?
|
||||
|
||||
For the time being Spring Cloud Contract Verifier is a JVM based tool. So it could be your first pick when you're already creating
|
||||
software for the JVM. This project has a lot of really interesting features but especially quite a few of them definitely make
|
||||
Spring Cloud Contract Verifier stand out on the "market" of Consumer Driven Contract (CDC) tooling. Out of many the most interesting are:
|
||||
|
||||
- Possibility to do CDC with messaging
|
||||
- Clear and easy to use, statically typed DSL
|
||||
- Possibility to copy paste your current JSON file to the contract and only edit its elements
|
||||
- Automatic generation of tests from the defined Contract
|
||||
- Stub Runner functionality - the stubs are automatically downloaded at runtime from Nexus / Artifactory
|
||||
- Spring Cloud integration - no discovery service is needed for integration tests
|
||||
|
||||
==== What is this value(consumer(), producer()) ?
|
||||
|
||||
One of the biggest challenges related to stubs is their reusability. Only if they can be vastly used, will they serve their purpose.
|
||||
What typically makes that difficult are the hard-coded values of request / response elements. For example dates or ids.
|
||||
Imagine the following JSON request
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "2016-10-10 20:10:15",
|
||||
"id" : "9febab1c-6f36-4a0b-88d6-3b6a6d81cd4a",
|
||||
"body" : "foo"
|
||||
}
|
||||
----
|
||||
|
||||
and JSON response
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "2016-10-10 21:10:15",
|
||||
"id" : "c4231e1f-3ca9-48d3-b7e7-567d55f0d051",
|
||||
"body" : "bar"
|
||||
}
|
||||
----
|
||||
|
||||
Imagine the pain required to set proper value of the `time` field (let's assume that this content is generated by the
|
||||
database) by changing the clock in the system or providing stub implementations of data providers. The same is related
|
||||
to the field called `id`. Will you create a stubbed implementation of UUID generator? Makes little sense...
|
||||
|
||||
So as a consumer you would like to send a request that matches any form of a time or any UUID. That way your system
|
||||
will work as usual - will generate data and you won't have to stub anything out. Let's assume that in case of the aforementioned
|
||||
JSON the most important part is the `body` field. You can focus on that and provide matching for other fields. In other words
|
||||
you would like the stub to work like this:
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "SOMETHING THAT MATCHES TIME",
|
||||
"id" : "SOMETHING THAT MATCHES UUID",
|
||||
"body" : "foo"
|
||||
}
|
||||
----
|
||||
|
||||
As far as the response goes as a consumer you need a concrete value that you can operate on. So such a JSON is valid
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "2016-10-10 21:10:15",
|
||||
"id" : "c4231e1f-3ca9-48d3-b7e7-567d55f0d051",
|
||||
"body" : "bar"
|
||||
}
|
||||
----
|
||||
|
||||
As you could see in the previous sections we generate tests from contracts. So from the producer's side the situation looks
|
||||
much different. We're parsing the provided contract and in the test we want to send a real request to your endpoints.
|
||||
So for the case of a producer for the request we can't have any sort of matching. We need concrete values that the
|
||||
producer's backend can work on. Such a JSON would be a valid one:
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "2016-10-10 20:10:15",
|
||||
"id" : "9febab1c-6f36-4a0b-88d6-3b6a6d81cd4a",
|
||||
"body" : "foo"
|
||||
}
|
||||
----
|
||||
|
||||
On the other hand from the point of view of the validity of the contract the response doesn't necessarily have to
|
||||
contain concrete values of `time` or `id`. Let's say that you generate those on the producer side - again, you'd
|
||||
have to do a lot of stubbing to ensure that you always return the same values. That's why from the producer's side
|
||||
what you might want is the following response:
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"time" : "SOMETHING THAT MATCHES TIME",
|
||||
"id" : "SOMETHING THAT MATCHES UUID",
|
||||
"body" : "bar"
|
||||
}
|
||||
----
|
||||
|
||||
How can you then provide one time a matcher for the consumer and a concrete value for the producer and vice versa?
|
||||
In Spring Cloud Contract we're allowing you to provide a *dynamic value*. That means that it can differ for both
|
||||
sides of the communication. You can pass the values:
|
||||
|
||||
Either via the `value` method
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
value(consumer(...), producer(...))
|
||||
value(stub(...), test(...))
|
||||
value(client(...), server(...))
|
||||
----
|
||||
|
||||
or using the `$()` method
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
$(consumer(...), producer(...))
|
||||
$(stub(...), test(...))
|
||||
$(client(...), server(...))
|
||||
----
|
||||
|
||||
You can read more about this in the https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html#_contract_dsl[Contract DSL section].
|
||||
|
||||
Calling `value()` or `$()` tells Spring Cloud Contract that you will be passing a dynamic value.
|
||||
Inside the `consumer()` method you pass the value that should be used on the consumer side (in the generated stub).
|
||||
Inside the `producer()` method you pass the value that should be used on the producer side (in the generated test).
|
||||
|
||||
TIP: If on one side you have passed the regular expression and you haven't passed the other, then the
|
||||
other side will get auto-generated.
|
||||
|
||||
Most often you will use that method together with the `regex` helper method. E.g. `consumer(regex('[0-9]{10}'))`.
|
||||
|
||||
To sum it up the contract for the aforementioned scenario would look more or less like this (the regular expression
|
||||
for time and UUID are simplified and most likely invalid but we want to keep things very simple in this example):
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
org.springframework.cloud.contract.spec.Contract.make {
|
||||
request {
|
||||
method 'GET'
|
||||
url '/someUrl'
|
||||
body([
|
||||
time : value(consumer(regex('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-2][0-9]-[0-5][0-9]-[0-5][0-9]')),
|
||||
id: value(consumer(regex('[0-9a-zA-z]{8}-[0-9a-zA-z]{4}-[0-9a-zA-z]{4}-[0-9a-zA-z]{12}'))
|
||||
body: "foo"
|
||||
])
|
||||
}
|
||||
response {
|
||||
status 200
|
||||
body([
|
||||
time : value(producer(regex('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-2][0-9]-[0-5][0-9]-[0-5][0-9]')),
|
||||
id: value([producer(regex('[0-9a-zA-z]{8}-[0-9a-zA-z]{4}-[0-9a-zA-z]{4}-[0-9a-zA-z]{12}'))
|
||||
body: "bar"
|
||||
])
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
IMPORTANT: Please read the http://groovy-lang.org/json.html[Groovy docs related to JSON] to understand how to
|
||||
properly structure the request / response bodies.
|
||||
|
||||
==== How to do Stubs versioning?
|
||||
|
||||
===== API Versioning
|
||||
|
||||
Let's try to answer a question what versioning really means. If you're referring to the API version then there are
|
||||
different approaches.
|
||||
|
||||
- use Hypermedia, links and do not version your API by any means
|
||||
- pass versions through headers / urls
|
||||
|
||||
I will not try to answer a question which approach is better. Whatever suit your needs and allows you to generate
|
||||
business value should be picked.
|
||||
|
||||
Let's assume that you do version your API. In that case you should provide as many contracts as many versions you support.
|
||||
You can create a subfolder for every version or append it to th contract name - whatever suits you more.
|
||||
|
||||
===== JAR versioning
|
||||
|
||||
If by versioning you mean the version of the JAR that contains the stubs then there are essentially two main approaches.
|
||||
|
||||
Let's assume that you're doing Continuous Delivery / Deployment which means that you're generating a new version of
|
||||
the jar each time you go through the pipeline and that jar can go to production at any time. For example your jar version
|
||||
looks like this (it got built on the 20.10.2016 at 20:15:21) :
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
1.0.0.20161020-201521-RELEASE
|
||||
----
|
||||
|
||||
In that case your generated stub jar will look like this.
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
1.0.0.20161020-201521-RELEASE-stubs.jar
|
||||
----
|
||||
|
||||
In this case you should inside your `application.yml` or `@AutoConfigureStubRunner` when referencing stubs provide the
|
||||
latest version of the stubs. You can do that by passing the `+` sign. Example
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:8080"})
|
||||
----
|
||||
|
||||
If the versioning however is fixed (e.g. `1.0.4.RELEASE` or `2.1.1`) then you have to set the concrete value of the jar
|
||||
version. Example for 2.1.1.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:2.1.1:stubs:8080"})
|
||||
----
|
||||
|
||||
===== Dev or prod stubs
|
||||
|
||||
You can manipulate the classifier to run the tests against current development version of the stubs of other services
|
||||
or the ones that were deployed to production. If you alter your build to deploy the stubs with the `prod-stubs` classifier
|
||||
once you reach production deployment then you can run tests in one case with dev stubs and one with prod stubs.
|
||||
|
||||
Example of tests using development version of stubs
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:8080"})
|
||||
----
|
||||
|
||||
Example of tests using production version of stubs
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:prod-stubs:8080"})
|
||||
----
|
||||
|
||||
You can pass those values also via properties from your deployment pipeline.
|
||||
|
||||
==== Common repo with contracts
|
||||
|
||||
Another way of storing contracts other than having them with the producer is keeping them in a common place.
|
||||
It can be related to security issues where the consumers can't clone the producer's code. Also if you keep
|
||||
contracts in a single place then you, as a producer, will know how many consumers you have and which
|
||||
consumer will you break with your local changes.
|
||||
|
||||
===== Repo structure
|
||||
|
||||
Let's assume that we have a producer with coordinates `com.example:server` and 3 consumers: `client1`,
|
||||
`client2`, `client3`. Then in the repository with common contracts you would have the following setup
|
||||
(which you can checkout https://github.com/spring-cloud/spring-cloud-contract/tree/{branch}/samples/standalone/contracts[here]:
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
├── com
|
||||
│ └── example
|
||||
│ └── server
|
||||
│ ├── client1
|
||||
│ │ └── expectation.groovy
|
||||
│ ├── client2
|
||||
│ │ └── expectation.groovy
|
||||
│ ├── client3
|
||||
│ │ └── expectation.groovy
|
||||
│ └── pom.xml
|
||||
├── mvnw
|
||||
├── mvnw.cmd
|
||||
├── pom.xml
|
||||
└── src
|
||||
└── assembly
|
||||
└── contracts.xml
|
||||
----
|
||||
|
||||
As you can see the under the slash-delimited groupid `/` artifact id folder (`com/example/server`) you have
|
||||
expectations of the 3 consumers (`client1`, `client2` and `client3`). Expectations are the standard Groovy DSL
|
||||
contract files as described throughout this documentation. This repository has to produce a JAR file that maps
|
||||
one to one to the contents of the repo.
|
||||
|
||||
Example of a `pom.xml` inside the `server` folder.
|
||||
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{introduction_url}/samples/standalone/contracts/com/example/server/pom.xml[indent=0]
|
||||
----
|
||||
|
||||
As you can see there are no dependencies other than the Spring Cloud Contract Maven Plugin.
|
||||
Those poms are necessary for the consumer side to run `mvn clean install -DskipTests` to locally install
|
||||
stubs of the producer project.
|
||||
|
||||
The `pom.xml` in the root folder can look like this:
|
||||
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{introduction_url}/samples/standalone/contracts/pom.xml[indent=0]
|
||||
----
|
||||
|
||||
It's using the assembly plugin in order to build the JAR with all the contracts. Example of such setup is here:
|
||||
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{introduction_url}/samples/standalone/contracts/src/assembly/contracts.xml[indent=0]
|
||||
----
|
||||
|
||||
===== Workflow
|
||||
|
||||
The workflow would look similar to the one presented in the `Step by step guide to CDC`. The only difference
|
||||
is that the producer doesn't own the contracts anymore. So the consumer and the producer have to work on
|
||||
common contracts in a common repository.
|
||||
|
||||
====== Consumer
|
||||
|
||||
When the *consumer* wants to work on the contracts offline, instead of cloning the producer code, the
|
||||
consumer team clones the common repository, goes to the required producer's folder (e.g. `com/example/server`)
|
||||
and runs `mvn clean install -DskipTests` to install locally the stubs converted from the contracts.
|
||||
|
||||
TIP: You need to have http://maven.apache.org/download.cgi[Maven installed locally]
|
||||
|
||||
====== Producer
|
||||
|
||||
As a *producer* it's enough to alter the Spring Cloud Contract Verifier to provide the URL and the dependency
|
||||
of the JAR containing the contracts:
|
||||
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{introduction_url}/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-remote-contracts/pom-with-repo.xml[tags=remote_config,indent=0]
|
||||
----
|
||||
|
||||
With this setup the JAR with groupid `com.example.standalone` and artifactid `contracts` will be downloaded
|
||||
from `http://link/to/your/nexus/or/artifactory/or/sth`. It will be then unpacked in a local temporary folder
|
||||
and contracts present under the `com/example/server` will be picked as the ones used to generate the
|
||||
tests and the stubs. Due to this convention the producer team will know which consumer teams will be broken
|
||||
when some incompatible changes are done.
|
||||
|
||||
The rest of the flow looks the same.
|
||||
|
||||
==== Can I have multiple base classes for tests?
|
||||
|
||||
Yes! Check out the https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html#_different_base_classes_for_contracts[Different base classes for contracts] sections
|
||||
of either Gradle or Maven plugins.
|
||||
|
||||
==== How can I debug the request/response being sent by the generated tests client?
|
||||
|
||||
The generated tests all boil down to RestAssured in some form or fashion which relies on https://hc.apache.org/httpcomponents-client-ga/[Apache HttpClient]. HttpClient has a facility called https://hc.apache.org/httpcomponents-client-ga/logging.html#Wire_Logging[wire logging] which logs the entire request and response to HttpClient. Spring Boot has a logging https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html[common application property] for doing this sort of thing, just add this to your application properties
|
||||
[source,properties,indent=0]
|
||||
----
|
||||
logging.level.org.apache.http.wire=DEBUG
|
||||
----
|
||||
|
||||
==== How can I debug the mapping/request/response being sent by WireMock?
|
||||
|
||||
Starting from version `1.2.0` we turn on WireMock logging to
|
||||
info and the WireMock notifier to being verbose. Now you will
|
||||
exactly know what request was received by WireMock server and which
|
||||
matching response definition was picked.
|
||||
|
||||
To turn off this feature just bump WireMock logging to `ERROR`
|
||||
|
||||
[source,properties,indent=0]
|
||||
----
|
||||
logging.level.com.github.tomakehurst.wiremock=ERROR
|
||||
----
|
||||
|
||||
==== How can I see what got registered in the HTTP server stub?
|
||||
|
||||
You can use the `mappingsOutputFolder` property on `@AutoConfigureStubRunner` or `StubRunnerRule`
|
||||
to dump all mappings per artifact id. Also the port at which the given stub server was
|
||||
started will be attached.
|
||||
|
||||
==== Can I reference the request from the response?
|
||||
|
||||
Yes! With version 1.1.0 we've added such a possibility. On the HTTP stub server side we're providing support
|
||||
for this for WireMock. In case of other HTTP server stubs you'll have to implement the approach yourself.
|
||||
|
||||
==== Can I reference text from file?
|
||||
|
||||
Yes! With version 1.2.0 we've added such a possibility. It's enough to call `file(...)` method in the
|
||||
DSL and provide a path relative to where the contract lays.
|
||||
Here you can find some https://github.com/spring-cloud-samples/spring-cloud-contract-samples[samples].
|
||||
@@ -1,9 +1,9 @@
|
||||
=== Spring Cloud Contract Verifier Messaging
|
||||
== Spring Cloud Contract Verifier Messaging
|
||||
|
||||
Spring Cloud Contract Verifier allows you to verify your application that uses messaging as means of communication.
|
||||
All of our integrations are working with Spring but you can also create one yourself and use it.
|
||||
|
||||
==== Integrations
|
||||
=== Integrations
|
||||
|
||||
You can use one of the four integration configurations:
|
||||
|
||||
@@ -38,7 +38,7 @@ testCompile "org.springframework.cloud:spring-cloud-stream-test-support"
|
||||
----
|
||||
|
||||
|
||||
==== Manual Integration Testing
|
||||
=== Manual Integration Testing
|
||||
|
||||
The main interface used by the tests is the `org.springframework.cloud.contract.verifier.messaging.MessageVerifier`.
|
||||
It defines how to send and receive messages. You can create your own implementation to achieve the
|
||||
@@ -64,7 +64,7 @@ NOTE: If your tests require stubs as well, then
|
||||
`@AutoConfigureStubRunner` includes the messaging configuration, so
|
||||
you only need the one annotation.
|
||||
|
||||
==== Publisher side test generation
|
||||
=== Publisher side test generation
|
||||
|
||||
Having the `input` or `outputMessage` sections in your DSL will result in creation of tests on the publisher's side. By default
|
||||
JUnit tests will be created, however there is also a possibility to create Spock tests.
|
||||
@@ -82,7 +82,7 @@ IMPORTANT: The destination passed to `messageFrom` or `sentTo` can have differen
|
||||
|
||||
Example for Camel:
|
||||
|
||||
===== Scenario 1 (no input message)
|
||||
==== Scenario 1 (no input message)
|
||||
|
||||
For the given contract:
|
||||
|
||||
@@ -105,7 +105,7 @@ And the following Spock test would be created:
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=trigger_method_test]
|
||||
----
|
||||
|
||||
===== Scenario 2 (output triggered by input)
|
||||
==== Scenario 2 (output triggered by input)
|
||||
|
||||
For the given contract:
|
||||
|
||||
@@ -128,7 +128,7 @@ And the following Spock test would be created:
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=trigger_message_spock]
|
||||
----
|
||||
|
||||
===== Scenario 3 (no output message)
|
||||
==== Scenario 3 (no output message)
|
||||
|
||||
For the given contract:
|
||||
|
||||
@@ -151,7 +151,7 @@ And the following Spock test would be created:
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=trigger_no_output_spock]
|
||||
----
|
||||
|
||||
==== Consumer Stub Side generation
|
||||
=== Consumer Stub Side generation
|
||||
|
||||
Unlike the HTTP part - in Messaging we need to publish the Groovy DSL inside the JAR with a stub. Then it's parsed on the consumer side
|
||||
and proper stubbed routes are created.
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
=== Spring Cloud Contract Verifier HTTP
|
||||
== Spring Cloud Contract Verifier Setup
|
||||
|
||||
==== Gradle Project
|
||||
=== Gradle Project
|
||||
|
||||
===== Prerequisites
|
||||
==== Prerequisites
|
||||
|
||||
In order to use Spring Cloud Contract Verifier with WireMock you have to use Gradle or Maven plugin.
|
||||
|
||||
WARNING: If you want to use Spock in your projects you have to add separately
|
||||
the `spock-core` and `spock-spring` modules. Check http://spockframework.github.io/[Spock docs for more information]
|
||||
|
||||
====== Add gradle plugin with dependencies
|
||||
==== Add gradle plugin with dependencies
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
@@ -41,7 +41,7 @@ dependencies {
|
||||
}
|
||||
----
|
||||
|
||||
====== Gradle and Rest Assured 2.0
|
||||
==== Gradle and Rest Assured 2.0
|
||||
|
||||
By default Rest Assured 3.x is added to the classpath. However in order to give the users the
|
||||
opportunity to use Rest Assured 2.x it's enough to add it to the plugins classpath.
|
||||
@@ -71,7 +71,7 @@ depenendencies {
|
||||
That way the plugin will automatically see that Rest Assured 2.x is present on the classpath
|
||||
and will modify the imports accordingly.
|
||||
|
||||
====== Snapshot versions for Gradle
|
||||
==== Snapshot versions for Gradle
|
||||
|
||||
Add the additional snapshot repository to your build.gradle to use snapshot versions which are automatically uploaded after every successful build:
|
||||
|
||||
@@ -81,7 +81,7 @@ include::{standalone_samples_path}/http-server/build.gradle[tags=repos,indent=0]
|
||||
}
|
||||
----
|
||||
|
||||
====== Add stubs
|
||||
==== Add stubs
|
||||
|
||||
By default Spring Cloud Contract Verifier is looking for stubs in `src/test/resources/contracts` directory.
|
||||
|
||||
@@ -100,11 +100,11 @@ Spring Cloud Contract Verifier will create test class `defaultBasePackage.MyServ
|
||||
- `shouldCreateUser()`
|
||||
- `shouldReturnUser()`
|
||||
|
||||
===== Run plugin
|
||||
==== Run plugin
|
||||
|
||||
Plugin registers itself to be invoked before `check` task. You have nothing to do as long as you want it to be part of your build process. If you just want to generate tests please invoke `generateContractTests` task.
|
||||
|
||||
===== Default setup
|
||||
==== Default setup
|
||||
|
||||
Default Gradle Plugin setup creates the following Gradle part of the build (it's a pseudocode)
|
||||
|
||||
@@ -156,7 +156,7 @@ publishing {
|
||||
}
|
||||
----
|
||||
|
||||
===== Configure plugin
|
||||
==== Configure plugin
|
||||
|
||||
To change default configuration just add `contracts` snippet to your Gradle config
|
||||
|
||||
@@ -169,7 +169,7 @@ contracts {
|
||||
}
|
||||
----
|
||||
|
||||
====== Configuration options
|
||||
==== Configuration options
|
||||
|
||||
- **testMode** - defines mode for acceptance tests. By default MockMvc which is based on Spring's MockMvc. It can also be changed to **JaxRsClient** or to **Explicit** for real HTTP calls.
|
||||
- **imports** - array with imports that should be included in generated tests (for example ['org.myorg.Matchers']). By default empty array []
|
||||
@@ -192,7 +192,7 @@ The following properties are used when you want to provide where the JAR with co
|
||||
- **contractsPath** - if contract deps are downloaded will default to `groupid/artifactid` where `groupid` will be slash separated. Otherwise will scan contracts under provided directory
|
||||
- **contractsWorkOffline** - in order not to download the dependencies each time you can download them once and work offline afterwards (reuse local Maven repo)
|
||||
|
||||
====== Single base class for all tests
|
||||
==== Single base class for all tests
|
||||
|
||||
When using Spring Cloud Contract Verifier in default MockMvc you need to create a base specification for all generated acceptance tests. In this class you need to point to endpoint which should be verified.
|
||||
|
||||
@@ -204,7 +204,7 @@ include::{plugins_path}/spring-cloud-contract-gradle-plugin/src/test/resources/f
|
||||
In case of using `Explicit` mode, you can use base class to initialize the whole tested app similarly as in regular integration tests. In case of `JAXRSCLIENT` mode this base class
|
||||
should also contain `protected WebTarget webTarget` field, right now the only option to test JAX-RS API is to start a web server.
|
||||
|
||||
====== Different base classes for contracts
|
||||
==== Different base classes for contracts
|
||||
|
||||
If your base classes differ between contracts you can tell the Spring Cloud Contract plugin which class should get
|
||||
extended by the autogenerated tests. You have two options:
|
||||
@@ -241,7 +241,7 @@ By providing the `baseClassForTests` we have a fallback in case mapping didn't s
|
||||
the `packageWithBaseClasses` as fallback). That way the tests generated from `src/test/resources/contract/com/` contracts
|
||||
will be extending the `com.example.ComBase` whereas the rest of tests will extend `com.example.FooBase`.
|
||||
|
||||
===== Invoking generated tests
|
||||
==== Invoking generated tests
|
||||
|
||||
To ensure that provider side is complaint with defined contracts, you need to invoke:
|
||||
|
||||
@@ -250,7 +250,7 @@ To ensure that provider side is complaint with defined contracts, you need to in
|
||||
./gradlew generateContractTests test
|
||||
----
|
||||
|
||||
===== Spring Cloud Contract Verifier on consumer side
|
||||
==== Spring Cloud Contract Verifier on consumer side
|
||||
|
||||
In consumer service you need to configure Spring Cloud Contract Verifier plugin in exactly the same way as in case of provider. If you don't want to use Stub Runner then you need to copy contracts stored in
|
||||
`src/test/resources/contracts` and generate WireMock json stubs using:
|
||||
@@ -291,9 +291,9 @@ class LoanApplicationServiceSpec extends Specification {
|
||||
|
||||
Underneath LoanApplication makes a call to FraudDetection service. This request is handled by WireMock server configured using stubs generated by Spring Cloud Contract Verifier.
|
||||
|
||||
==== Using in your Maven project
|
||||
=== Using in your Maven project
|
||||
|
||||
===== Add maven plugin
|
||||
==== Add maven plugin
|
||||
|
||||
Add the Spring Cloud Contract BOM
|
||||
|
||||
@@ -311,7 +311,7 @@ include::{standalone_samples_path}/http-server/pom.xml[tags=contract_maven_plugi
|
||||
|
||||
You can read more in the https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract-maven-plugin/[Spring Cloud Contract Maven Plugin Docs]
|
||||
|
||||
====== Maven and Rest Assured 2.0
|
||||
==== Maven and Rest Assured 2.0
|
||||
|
||||
By default Rest Assured 3.x is added to the classpath. However in order to give the users the
|
||||
opportunity to use Rest Assured 2.x it's enough to add it to the plugins classpath.
|
||||
@@ -368,7 +368,7 @@ opportunity to use Rest Assured 2.x it's enough to add it to the plugins classpa
|
||||
That way the plugin will automatically see that Rest Assured 3.x is present on the classpath
|
||||
and will modify the imports accordingly.
|
||||
|
||||
====== Snapshot versions for Maven
|
||||
==== Snapshot versions for Maven
|
||||
|
||||
For Snapshot / Milestone versions you have to add the following section to your `pom.xml`
|
||||
|
||||
@@ -377,7 +377,7 @@ For Snapshot / Milestone versions you have to add the following section to your
|
||||
include::{standalone_samples_path}/http-server/pom.xml[tags=repos,indent=0]
|
||||
----
|
||||
|
||||
===== Add stubs
|
||||
==== Add stubs
|
||||
|
||||
By default Spring Cloud Contract Verifier is looking for stubs in `src/test/resources/contracts` directory.
|
||||
Directory containing stub definitions is treated as a class name, and each stub definition is treated as a single test.
|
||||
@@ -394,11 +394,11 @@ Spring Cloud Contract Verifier will create test class `defaultBasePackage.MyServ
|
||||
- `shouldCreateUser()`
|
||||
- `shouldReturnUser()`
|
||||
|
||||
===== Run plugin
|
||||
==== Run plugin
|
||||
|
||||
Plugin goal `generateTests` is assigned to be invoked in phase `generate-test-sources`. You have nothing to do as long as you want it to be part of your build process. If you just want to generate tests please invoke `generateTests` goal.
|
||||
|
||||
===== Configure plugin
|
||||
==== Configure plugin
|
||||
|
||||
To change default configuration just add `configuration` section to plugin definition or `execution` definition.
|
||||
|
||||
@@ -423,7 +423,7 @@ To change default configuration just add `configuration` section to plugin defin
|
||||
</plugin>
|
||||
----
|
||||
|
||||
====== Important configuration options
|
||||
==== Important configuration options
|
||||
|
||||
- **testMode** - defines mode for acceptance tests. By default `MockMvc` which is based on Spring's MockMvc. It can also be changed to `JaxRsClient` or to `Explicit` for real HTTP calls.
|
||||
- **basePackageForTests** - specifies base package for all generated tests. If not set the value will be picked from `baseClassForTests`'s package and from
|
||||
@@ -457,7 +457,7 @@ If you want to download your contract definitions from a Maven repository you ca
|
||||
We cache only non-snapshot, explicitly provided versions (e.g. `+` or `1.0.0.BUILD-SNAPSHOT` won't get cached).
|
||||
By default this feature is turned on.
|
||||
|
||||
====== Single base class for all tests
|
||||
==== Single base class for all tests
|
||||
|
||||
When using Spring Cloud Contract Verifier in default MockMvc you need to create a base specification for all generated acceptance tests.
|
||||
In this class you need to point to endpoint which should be verified.
|
||||
@@ -479,7 +479,7 @@ class MvcSpec extends Specification {
|
||||
|
||||
In case of using `Explicit` mode, you can use base class to initialize the whole tested app similarly as in regular integration tests. In case of `JAXRSCLIENT` mode this base class should also contain `protected WebTarget webTarget` field, right now the only option to test JAX-RS API is to start a web server.
|
||||
|
||||
====== Different base classes for contracts
|
||||
==== Different base classes for contracts
|
||||
|
||||
If your base classes differ between contracts you can tell the Spring Cloud Contract plugin which class should get
|
||||
extended by the autogenerated tests. You have two options:
|
||||
@@ -517,7 +517,7 @@ By providing the `baseClassForTests` we have a fallback in case mapping didn't s
|
||||
the `packageWithBaseClasses` as fallback). That way the tests generated from `src/test/resources/contract/com/` contracts
|
||||
will be extending the `com.example.ComBase` whereas the rest of tests will extend `com.example.FooBase`.
|
||||
|
||||
===== Invoking generated tests
|
||||
==== Invoking generated tests
|
||||
|
||||
Spring Cloud Contract Maven Plugin generates verification code into directory `/generated-test-sources/contractVerifier` and attach this directory to `testCompile` goal.
|
||||
|
||||
@@ -557,9 +557,9 @@ For Groovy Spock code use:
|
||||
|
||||
To ensure that provider side is complaint with defined contracts, you need to invoke `mvn generateTest test`
|
||||
|
||||
===== FAQ with Maven Plugin
|
||||
==== FAQ with Maven Plugin
|
||||
|
||||
====== Maven Plugin and STS
|
||||
==== Maven Plugin and STS
|
||||
|
||||
In case you see the following exception while using STS
|
||||
|
||||
@@ -616,7 +616,7 @@ In order to fix this issue just provide the following section in your `pom.xml`
|
||||
</build>
|
||||
----
|
||||
|
||||
===== Spring Cloud Contract Verifier on consumer side
|
||||
==== Spring Cloud Contract Verifier on consumer side
|
||||
|
||||
You can actually use the Spring Cloud Contract Verifier also for the consumer side!
|
||||
You can use the plugin so that it only converts the contracts and generates the stubs.
|
||||
@@ -676,7 +676,7 @@ public class LoanApplicationServiceTests {
|
||||
Underneath `LoanApplication` makes a call to the `FraudDetection` service. This request is handled by
|
||||
a WireMock server configured using stubs generated by Spring Cloud Contract Verifier.
|
||||
|
||||
==== Scenarios
|
||||
=== Scenarios
|
||||
|
||||
It's possible to handle scenarios with Spring Cloud Contract Verifier. All you need to do is to stick to proper naming convention while creating your contracts. The convention requires to include order number followed by the underscore.
|
||||
|
||||
@@ -699,7 +699,7 @@ More details about WireMock scenarios can be found under http://wiremock.org/sta
|
||||
|
||||
Spring Cloud Contract Verifier will also generate tests with guaranteed order of execution.
|
||||
|
||||
==== Stubs and transitive dependencies
|
||||
=== Stubs and transitive dependencies
|
||||
|
||||
The Maven and Gradle plugin that we're created are adding the tasks that create the stubs jar for you. What can be problematic
|
||||
is that when reusing the stubs you can by mistake import all of that stub dependencies! When building a Maven artifact
|
||||
@@ -1,4 +1,4 @@
|
||||
=== Spring Cloud Contract Stub Runner
|
||||
== Spring Cloud Contract Stub Runner
|
||||
|
||||
One of the issues that you could have encountered while using Spring Cloud Contract Verifier was to pass the generated WireMock JSON stubs from the server side to the client side (or various clients).
|
||||
The same takes place in terms of client side generation for messaging.
|
||||
@@ -8,7 +8,7 @@ Copying the JSON files / setting the client side for messaging manually is out o
|
||||
That's why we'll introduce Spring Cloud Contract Stub Runner that can download and run the stubs
|
||||
automatically for you.
|
||||
|
||||
==== Snapshot versions
|
||||
=== Snapshot versions
|
||||
|
||||
Add the additional snapshot repository to your build.gradle to use snapshot versions which are automatically uploaded after every successful build:
|
||||
|
||||
@@ -24,7 +24,7 @@ include::{standalone_samples_path}/http-server/pom.xml[tags=repos,indent=0]
|
||||
include::{standalone_samples_path}/http-server/build.gradle[tags=repos,indent=0]
|
||||
----
|
||||
|
||||
==== Publishing stubs as JARs
|
||||
=== 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.
|
||||
|
||||
@@ -58,7 +58,7 @@ include::{stubrunner_core_path}/README.adoc[]
|
||||
Some of the properties that are repetitive can be set using system properties or configuration properties (for Spring). Here are their names with their default values:
|
||||
|
||||
[frame="topbot",options="header"]
|
||||
|======================
|
||||
|===============
|
||||
| Property name | Default value | Description
|
||||
|stubrunner.minPort|10000| Minimal value of a port for a started WireMock with stubs
|
||||
|stubrunner.maxPort|15000| Minimal value of a port for a started WireMock with stubs
|
||||
@@ -70,9 +70,9 @@ Some of the properties that are repetitive can be set using system properties or
|
||||
|stubrunner.password|| Optional password to access the tool that stores the JARs with stubs
|
||||
|stubrunner.stubsPerConsumer|false| Set to `true` if you want to use different stubs per each consumer instead of registering all stubs for every consumer
|
||||
|stubrunner.consumerName|| If you want to use stubs per consumer and want to override the consumer name just change this value
|
||||
|======================
|
||||
|===============
|
||||
|
||||
===== Stub runner stubs ids
|
||||
==== Stub runner stubs ids
|
||||
|
||||
You can provide the stubs to download via the `stubrunner.ids` system property. They follow the following pattern:
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
=== Stub Runner for Messaging
|
||||
== Stub Runner for Messaging
|
||||
|
||||
Stub Runner has the functionality to run the published stubs in memory. It can integrate with the following frameworks out of the box
|
||||
|
||||
@@ -9,7 +9,7 @@ Stub Runner has the functionality to run the published stubs in memory. It can i
|
||||
|
||||
It also provides points of entry to integrate with any other solution on the market.
|
||||
|
||||
==== Stub triggering
|
||||
=== Stub triggering
|
||||
|
||||
To trigger a message it's enough to use the `StubTrigger` interface:
|
||||
|
||||
@@ -22,28 +22,28 @@ For convenience the `StubFinder` interface extends `StubTrigger` so it's enough
|
||||
|
||||
`StubTrigger` gives you the following options to trigger a message:
|
||||
|
||||
===== Trigger by label
|
||||
==== Trigger by label
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy[tags=client_trigger,indent=0]
|
||||
----
|
||||
|
||||
====== Trigger by group and artifact ids
|
||||
==== Trigger by group and artifact ids
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy[tags=trigger_group_artifact,indent=0]
|
||||
----
|
||||
|
||||
====== Trigger by artifact ids
|
||||
==== Trigger by artifact ids
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy[tags=trigger_artifact,indent=0]
|
||||
----
|
||||
|
||||
===== Trigger all messages
|
||||
==== Trigger all messages
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
|
||||
Reference in New Issue
Block a user