Added support for Stub Runner and Pact Broker

fixes gh-191
commit 533f1d3d0e8f6dcd37677bfef555fc2ea86bc1b1
Author: Tim Ysewyn <Tim.Ysewyn@me.com>
Date:   Wed Mar 7 15:56:48 2018 +0100

    Upgraded pact-jvm-model to 3.5.13
This commit is contained in:
Marcin Grzejszczak
2018-04-02 22:50:40 +02:00
parent de529e222e
commit 6402e14f3c
82 changed files with 953 additions and 395 deletions

View File

@@ -1382,6 +1382,7 @@ org.springframework.cloud.contract.spec.ContractConverter=\
org.springframework.cloud.contract.verifier.converter.YamlContractConverter
----
[[pact-converter]]
==== Pact Converter
Spring Cloud Contract includes support for https://docs.pact.io/[Pact] representation of
@@ -1675,3 +1676,76 @@ properties
|1000
|Number of millis to wait between attempts to push the commits to `origin`
|===
[[pact-stub-downloader]]
=== Using the Pact Stub Downloader
Whenever the `repositoryRoot` starts with a Pact protocol
(starts with `pact://`), the stub downloader will try
to fetch the Pact contract definitions from the Pact Broker.
Whatever is set after `pact://` will be parsed as the Pact Broker URL.
Either via environment variables, system properties, properties set
inside the plugin or contracts repository configuration you can
tweak the downloader's behaviour. Below you can find the list of
properties
.SCM Stub Downloader properties
|===
|Type of a property |Name of the property | Description
|
* `pactbroker.host` (plugin prop)
* `stubrunner.properties.pactbroker.host` (system prop)
* `STUBRUNNER_PROPERTIES_PACTBROKER_HOST` (env prop)
|Host from URL passed to `repositoryRoot`
|What is the URL of Pact Broker
|
* `pactbroker.port` (plugin prop)
* `stubrunner.properties.pactbroker.port` (system prop)
* `STUBRUNNER_PROPERTIES_PACTBROKER_PORT` (env prop)
|Port from URL passed to `repositoryRoot`
|What is the port of Pact Broker
|
* `pactbroker.protocol` (plugin prop)
* `stubrunner.properties.pactbroker.protocol` (system prop)
* `STUBRUNNER_PROPERTIES_PACTBROKER_PROTOCOL` (env prop)
|Protocol from URL passed to `repositoryRoot`
|What is the protocol of Pact Broker
|
* `pactbroker.tags` (plugin prop)
* `stubrunner.properties.pactbroker.tags` (system prop)
* `STUBRUNNER_PROPERTIES_PACTBROKER_TAGS` (env prop)
|Version of the stub, or `latest` if version is `+`
|What tags should be used to fetch the stub
|
* `pactbroker.auth.scheme` (plugin prop)
* `stubrunner.properties.pactbroker.auth.scheme` (system prop)
* `STUBRUNNER_PROPERTIES_PACTBROKER_AUTH_SCHEME` (env prop)
|`Basic`
|What kind of authentication should be used to connect to the Pact Broker
|
* `pactbroker.auth.username` (plugin prop)
* `stubrunner.properties.pactbroker.auth.username` (system prop)
* `STUBRUNNER_PROPERTIES_PACTBROKER_AUTH_USERNAME` (env prop)
|
|Username used to connect to the Pact Broker
|
* `pactbroker.auth.password` (plugin prop)
* `stubrunner.properties.pactbroker.auth.password` (system prop)
* `STUBRUNNER_PROPERTIES_PACTBROKER_AUTH_PASSWORD` (env prop)
|
|Password used to connect to the Pact Broker
|
* `pactbroker.provider-name-with-group-id` (plugin prop)
* `stubrunner.properties.pactbroker.provider-name-with-group-id` (system prop)
* `STUBRUNNER_PROPERTIES_PACTBROKER_PROVIDER_NAME_WITH_GROUP_ID` (env prop)
|false
|When `true`, the provider name will be a combination of `groupId:artifactId`. If `false`, just `artifactId` is used
|===

View File

@@ -1,6 +1,5 @@
:introduction_url: https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/{branch}
:samples_branch: 2.0.x
:samples_branch: 2.0.x
== Spring Cloud Contract FAQ
@@ -707,6 +706,195 @@ to find stub definitions and contracts. E.g. for `com.example:foo:1.0.0` the pat
* Stub servers will be started and fed with mappings
* Messaging definitions will be read and used in the messaging tests
=== Can I use the Pact Broker?
When using http://pact.io/[Pact] you can use the https://github.com/pact-foundation/pact_broker[Pact Broker]
to store and share Pact definitions. Starting from Spring Cloud Contract
2.0.0 one can fetch Pact files from the Pact Broker to generate
tests and stubs.
As a prerequisite the Pact Converter and Pact Stub Downloader
are required. You have to add it via the `spring-cloud-contract-pact` dependency.
You can read more about it in the <<pact-converter>> section.
IMPORTANT: Pact follows the Consumer Contract convention. That means
that the Consumer creates the Pact definitions first, then
shares the files with the Producer. Those expectations are generated
from the Consumer's code and can break the Producer if the expectation
is not met.
==== Pact Consumer
The consumer uses Pact framework to generate Pact files. The
Pact files are sent to the Pact Broker. An example of such
setup can be found https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/{samples_branch}/consumer_pact[here].
==== Producer
For the producer, to use the Pact files from the Pact Broker, we can reuse the
same mechanism we use for external contracts. We route Spring Cloud Contract
to use the Pact implementation via the URL that contains
the `pact://` protocol. It's enough to pass the URL to the
Pact Broker.
.Maven
[source,xml,indent=0]
----
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>${spring-cloud-contract.version}</version>
<extensions>true</extensions>
<configuration>
<!-- Base class mappings etc. -->
<!-- We want to pick contracts from a Git repository -->
<contractsRepositoryUrl>pact://http://localhost:8085</contractsRepositoryUrl>
<!-- We reuse the contract dependency section to set up the path
to the folder that contains the contract definitions. In our case the
path will be /groupId/artifactId/version/contracts -->
<contractDependency>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<!-- When + is passed, a latest tag will be applied when fetching pacts -->
<version>+</version>
</contractDependency>
<!-- The contracts mode can't be classpath -->
<contractsMode>REMOTE</contractsMode>
</configuration>
<!-- Don't forget to add spring-cloud-contract-pact to the classpath! -->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-pact</artifactId>
<version>${spring-cloud-contract.version}</version>
</dependency>
</dependencies>
</plugin>
----
.Gradle
[source,gradle,indent=0]
----
buildscript {
repositories {
//...
}
dependencies {
// ...
// Don't forget to add spring-cloud-contract-pact to the classpath!
classpath "org.springframework.cloud:spring-cloud-contract-pact:${contractVersion}"
}
}
contracts {
// When + is passed, a latest tag will be applied when fetching pacts
contractDependency {
stringNotation = "${project.group}:${project.name}:+"
}
contractRepository {
repositoryUrl = "pact://http://localhost:8085"
}
// The mode can't be classpath
contractsMode = "REMOTE"
// Base class mappings etc.
}
----
With such a setup:
* Pact files will be downloaded from the Pact Broker
* Spring Cloud Contract will convert the Pact files into tests and stubs
* The JAR with the stubs gets automatically created as usual
==== Pact Consumer (Producer Contract approach)
In the scenario where you don't want to do Consumer Contract approach
(for every single consumer define the expectations) but you'd prefer
to do Producer Contracts (the producer provides the contracts and
publishes stubs), it's enough to use Spring Cloud Contract with
Stub Runner option.
First, remember to add Stub Runner and Spring Cloud Contract Pact module
as test dependencies.
.Maven
[source,xml,indent=0]
----
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- Don't forget to add spring-cloud-contract-pact to the classpath! -->
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-pact</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
----
.Gradle
[source,gradle,indent=0]
----
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
dependencies {
//...
testCompile("org.springframework.cloud:spring-cloud-starter-contract-stub-runner")
// Don't forget to add spring-cloud-contract-pact to the classpath!
testCompile("org.springframework.cloud:spring-cloud-contract-pact")
}
----
Next, just pass the URL of the Pact Broker to `repositoryRoot`, prefixed
with `pact://` protocol. E.g. `pact://http://localhost:8085`
[source,java,indent=0]
----
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureStubRunner(stubsMode = StubRunnerProperties.StubsMode.REMOTE,
ids = "com.example:beer-api-producer-pact",
repositoryRoot = "pact://http://localhost:8085")
public class BeerControllerTest {
//Inject the port of the running stub
@StubRunnerPort("beer-api-producer-pact") int producerPort;
//...
}
----
With such a setup:
* Pact files will be downloaded from the Pact Broker
* Spring Cloud Contract will convert the Pact files into stub definitions
* The stub servers will be started and fed with stubs
For more information about Pact support you can go to
the <<pact-stub-downloader>> section.
=== 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