Migrate Structure
This commit is contained in:
@@ -1,17 +0,0 @@
|
||||
== Spring Cloud Contract
|
||||
|
||||
You always need confidence when pushing new features into a new application or service in
|
||||
a distributed system. To that end, this project provides support for consumer-driven
|
||||
contracts and service schemas in Spring applications, covering a range of options for
|
||||
writing tests, publishing them as assets, and asserting that a contract is kept by
|
||||
producers and consumers -- for both HTTP and message-based interactions.
|
||||
|
||||
== Project page
|
||||
|
||||
You can read more about Spring Cloud Contract by going to https://spring.io/projects/spring-cloud-contract[the project page]
|
||||
|
||||
== Contributing
|
||||
|
||||
include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/docs/src/main/asciidoc/contributing.adoc[]
|
||||
|
||||
include::_building.adoc[]
|
||||
@@ -1,17 +0,0 @@
|
||||
IMPORTANT: The following properties can be passed as a system property (for example, `stubrunner.properties.git.branch`), as an environment variable (for example, `STUBRUNNER_PROPERTIES_GIT_BRANCH`), or as a property inside stub runner's annotation or a JUnit Rule (JUnit 4) or Extension (JUnit 5). In the latter case, you can pass the `git.branch` property instead of `stubrunner.properties.git.branch`.
|
||||
|
||||
.Stubrunner Properties Options
|
||||
|===
|
||||
|Name | Default | Description
|
||||
|
||||
|`stubrunner.properties.git.branch` | | When using the SCM-based approach, you can customize the branch name to check out.
|
||||
|`stubrunner.properties.git.commit-message` | Updating project [$project] with stubs | When using the SCM based approach, you can customize the commit message for created stubs. The `$project` text is replaced with the project name.
|
||||
|`stubrunner.properties.git.no-of-attempts` | `10` | When using the-SCM based approach, you can customize the number of retries to push the stubs to Git.
|
||||
|`stubrunner.properties.git.username` | | When using the SCM-based approach, you can pass the username to connect to the git repository.
|
||||
|`stubrunner.properties.git.password` | | When using the SCM-based approach, you can pass the password to connect to the git repository.
|
||||
|`stubrunner.properties.git.wait-between-attempts` | `1000` | When using the SCM-based approach, you can customize waiting time in ms between attempts to push the stubs to git.
|
||||
|`stubrunner.properties.git.ensure-git-suffix` | `true` | When using the SCM based approach, you can prevent stubrunner from adding `.git` to the repository URL by setting this property to `false`. This adds compatibility with git repositories which do not support such URLs, for example Azure DevOps.
|
||||
|
||||
|`stubrunner.properties.stubs.find-producer` | `false` | When using the `stubs` protocol, you can toggle this flag to search for contracts in the `group id / artifact id` instead of taking the stubs directly from the provided folder.
|
||||
|
||||
|===
|
||||
@@ -1,38 +0,0 @@
|
||||
:doctype: book
|
||||
:idprefix:
|
||||
:idseparator: -
|
||||
:toc: left
|
||||
:toclevels: 4
|
||||
:tabsize: 4
|
||||
:numbered:
|
||||
:sectanchors:
|
||||
:sectnums:
|
||||
:icons: font
|
||||
:hide-uri-scheme:
|
||||
:docinfo: shared,private
|
||||
|
||||
:sc-ext: java
|
||||
:project-full-name: Spring Cloud Contract
|
||||
|
||||
// project-specific attributes
|
||||
:core_path: {project-root}
|
||||
:plugins_path: {project-root}/spring-cloud-contract-tools
|
||||
:converters_path: {plugins_path}/spring-cloud-contract-converters
|
||||
:verifier_root_path: {core_path}/spring-cloud-contract-verifier
|
||||
:contract_spec_path: {core_path}/specs/spring-cloud-contract-spec-java
|
||||
:contract_spec_tests_path: {core_path}/specs/spring-cloud-contract-spec
|
||||
:contract_kotlin_spec_path: {core_path}/specs/spring-cloud-contract-spec-kotlin
|
||||
:samples_path: {core_path}/samples
|
||||
:verifier_core_path: {verifier_root_path}
|
||||
:stubrunner_core_path: {core_path}/spring-cloud-contract-stub-runner
|
||||
:standalone_samples_path: {samples_path}/standalone/dsl
|
||||
:standalone_messaging_samples_path: {samples_path}/standalone/dsl
|
||||
:standalone_restdocs_path: {samples_path}/standalone/restdocs
|
||||
:tests_path: {core_path}/tests
|
||||
:samples_branch: main
|
||||
:samples_url: https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/{samples_branch}
|
||||
:samples_code: https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/{samples_branch}
|
||||
:doc_samples: {samples_code}/wiremock-for-contract-docs
|
||||
:doc_samples_url: {samples_url}/wiremock-for-contract-docs
|
||||
:wiremock_tests: {core_path}/spring-cloud-contract-wiremock
|
||||
:introduction_url: {core_path}
|
||||
@@ -1,140 +0,0 @@
|
||||
== How to Build Spring Cloud Contract
|
||||
|
||||
=== Cloning the repository on Windows
|
||||
|
||||
While cloning this project on Windows, some files in the git repository may exceed the Windows maximum file path limit of 255 characters, which may
|
||||
result in an incorrectly (probably partially) checked out repository.
|
||||
|
||||
To resolve this issue, you can set the `core.longPaths` attribute to `true` or clone the Spring Cloud Contract repository.
|
||||
|
||||
To set the `core.longPaths` attribute to `true`, you have three options:
|
||||
|
||||
- Change it for all users of the machine (doing so requires administrator privileges):
|
||||
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
git config --system core.longPaths true
|
||||
git clone https://github.com/spring-cloud/spring-cloud-contract.git
|
||||
----
|
||||
|
||||
- Change it for the current user (no administrative privileges required):
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
git config --global core.longPaths true
|
||||
git clone https://github.com/spring-cloud/spring-cloud-contract.git
|
||||
----
|
||||
|
||||
- Change for just this repository (administrative privileges depend on where the repository is being cloned to):
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
git clone -c core.longPaths=true https://github.com/spring-cloud/spring-cloud-contract.git
|
||||
----
|
||||
|
||||
IMPORTANT: You need to have all the necessary Groovy plugins
|
||||
installed for your IDE to properly resolve the sources. For example, in
|
||||
Intellij IDEA, having both the Eclipse Groovy Compiler Plugin and the GMavenPlus Intellij
|
||||
Plugin results in properly imported project.
|
||||
|
||||
IMPORTANT: Spring Cloud Contract builds Docker images. Remember to
|
||||
have Docker installed.
|
||||
|
||||
IMPORTANT: If you want to run the build in offline mode, you must have Maven 3.5.2+ installed.
|
||||
|
||||
=== Project structure
|
||||
|
||||
The following listing shows the Spring Cloud Contract folder structure:
|
||||
|
||||
```
|
||||
├── config
|
||||
├── docker
|
||||
├── samples
|
||||
├── scripts
|
||||
├── specs
|
||||
├── spring-cloud-contract-dependencies
|
||||
├── spring-cloud-contract-shade
|
||||
├── spring-cloud-contract-starters
|
||||
├── spring-cloud-contract-stub-runner
|
||||
├── spring-cloud-contract-stub-runner-boot
|
||||
├── spring-cloud-contract-tools
|
||||
├── spring-cloud-contract-verifier
|
||||
├── spring-cloud-contract-wiremock
|
||||
└── tests
|
||||
```
|
||||
|
||||
The following list describes each of the top-level folders in the project structure:
|
||||
|
||||
- `config`: Folder contains setup for Spring Cloud Release Tools automated release process
|
||||
- `docker`: Folder contains docker images
|
||||
- `samples`: Folder contains test samples together with standalone ones used also to build documentation
|
||||
- `scripts`: Contains scripts to build and test `Spring Cloud Contract` with Maven, Gradle and standalone projects
|
||||
- `specs`: Contains specifications for the Contract DSL.
|
||||
- `spring-cloud-contract-dependencies`: Contains Spring Cloud Contract BOM
|
||||
- `spring-cloud-contract-shade`: Shaded dependencies used by the plugins
|
||||
- `spring-cloud-contract-starters`: Contains Spring Cloud Contract Starters
|
||||
- `spring-cloud-contract-spec`: Contains specification modules (contains concept of a Contract)
|
||||
- `spring-cloud-contract-stub-runner`: Contains Stub Runner related modules
|
||||
- `spring-cloud-contract-stub-runner-boot`: Contains Stub Runner Boot app
|
||||
- `spring-cloud-contract-tools`: Gradle and Maven plugin for `Spring Cloud Contract Verifier`
|
||||
- `spring-cloud-contract-verifier`: Core of the `Spring Cloud Contract Verifier` functionality
|
||||
- `spring-cloud-contract-wiremock`: All WireMock related functionality
|
||||
- `tests`: Integration tests for different messaging technologies
|
||||
|
||||
=== Commands
|
||||
|
||||
To build the core functionality together with the Maven Plugin, you can run the following
|
||||
command:
|
||||
|
||||
```
|
||||
./mvnw clean install -P integration
|
||||
```
|
||||
|
||||
Calling that function builds the core, the Maven plugin, and the Gradle plugin and runs
|
||||
end-to_end tests on the
|
||||
standalone samples in the proper order (both for Maven and Gradle).
|
||||
|
||||
To build only the Gradle Plugin, you can run the following commands:
|
||||
|
||||
```
|
||||
cd spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin
|
||||
./gradlew clean build
|
||||
```
|
||||
|
||||
=== Helpful scripts
|
||||
|
||||
We provide a couple of helpful scripts to build the project.
|
||||
|
||||
To build the project in parallel (by default, it uses four cores, but you can change it),
|
||||
run the following command:
|
||||
|
||||
```
|
||||
./scripts/parallelBuild.sh
|
||||
```
|
||||
|
||||
To use eight 8 cores, run the following command:
|
||||
|
||||
```
|
||||
CORES=8 ./scripts/parallelBuild.sh
|
||||
```
|
||||
|
||||
To build the project without any integration tests (by default, this uses one core), run
|
||||
the following command:
|
||||
|
||||
```
|
||||
./scripts/noIntegration.sh
|
||||
```
|
||||
|
||||
To use eight cores, run the following command:
|
||||
|
||||
```
|
||||
CORES=8 ./scripts/noIntegration.sh
|
||||
```
|
||||
|
||||
To generate the documentation (for both the root project and the maven plugin), run the
|
||||
following command:
|
||||
|
||||
```
|
||||
./scripts/generateDocs.sh
|
||||
```
|
||||
@@ -1,47 +0,0 @@
|
||||
|===
|
||||
|Name | Default | Description
|
||||
|
||||
|stubrunner.amqp.enabled | `+++false+++` | Whether to enable support for Stub Runner and AMQP.
|
||||
|stubrunner.amqp.mockCOnnection | `+++true+++` | Whether to enable support for Stub Runner and AMQP mocked connection factory.
|
||||
|stubrunner.classifier | `+++stubs+++` | The classifier to use by default in ivy co-ordinates for a stub.
|
||||
|stubrunner.cloud.consul.enabled | `+++true+++` | Whether to enable stubs registration in Consul.
|
||||
|stubrunner.cloud.delegate.enabled | `+++true+++` | Whether to enable DiscoveryClient's Stub Runner implementation.
|
||||
|stubrunner.cloud.enabled | `+++true+++` | Whether to enable Spring Cloud support for Stub Runner.
|
||||
|stubrunner.cloud.eureka.enabled | `+++true+++` | Whether to enable stubs registration in Eureka.
|
||||
|stubrunner.cloud.loadbalancer.enabled | `+++true+++` | Whether to enable Stub Runner's Spring Cloud Load Balancer integration.
|
||||
|stubrunner.cloud.stubbed.discovery.enabled | `+++true+++` | Whether Service Discovery should be stubbed for Stub Runner. If set to false, stubs will get registered in real service discovery.
|
||||
|stubrunner.cloud.zookeeper.enabled | `+++true+++` | Whether to enable stubs registration in Zookeeper.
|
||||
|stubrunner.consumer-name | | You can override the default {@code spring.application.name} of this field by setting a value to this parameter.
|
||||
|stubrunner.delete-stubs-after-test | `+++true+++` | If set to {@code false} will NOT delete stubs from a temporary folder after running tests.
|
||||
|stubrunner.fail-on-no-stubs | `+++true+++` | When enabled, this flag will tell stub runner to throw an exception when no stubs / contracts were found.
|
||||
|stubrunner.generate-stubs | `+++false+++` | When enabled, this flag will tell stub runner to not load the generated stubs, but convert the found contracts at runtime to a stub format and run those stubs.
|
||||
|stubrunner.http-server-stub-configurer | | Configuration for an HTTP server stub.
|
||||
|stubrunner.ids | `+++[]+++` | The ids of the stubs to run in "ivy" notation ([groupId]:artifactId:[version]:[classifier][:port]). {@code groupId}, {@code classifier}, {@code version} and {@code port} can be optional.
|
||||
|stubrunner.ids-to-service-ids | | Mapping of Ivy notation based ids to serviceIds inside your application. Example "a:b" -> "myService" "artifactId" -> "myOtherService"
|
||||
|stubrunner.integration.enabled | `+++true+++` | Whether to enable Stub Runner integration with Spring Integration.
|
||||
|stubrunner.jms.enabled | `+++true+++` | Whether to enable Stub Runner integration with Spring JMS.
|
||||
|stubrunner.kafka.enabled | `+++true+++` | Whether to enable Stub Runner integration with Spring Kafka.
|
||||
|stubrunner.kafka.initializer.enabled | `+++true+++` | Whether to allow Stub Runner to take care of polling for messages instead of the KafkaStubMessages component. The latter should be used only on the producer side.
|
||||
|stubrunner.mappings-output-folder | | Dumps the mappings of each HTTP server to the selected folder.
|
||||
|stubrunner.max-port | `+++15000+++` | Max value of a port for the automatically started WireMock server.
|
||||
|stubrunner.min-port | `+++10000+++` | Min value of a port for the automatically started WireMock server.
|
||||
|stubrunner.password | | Repository password.
|
||||
|stubrunner.properties | | Map of properties that can be passed to custom {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}.
|
||||
|stubrunner.proxy-host | | Repository proxy host.
|
||||
|stubrunner.proxy-port | | Repository proxy port.
|
||||
|stubrunner.server-id | |
|
||||
|stubrunner.stream.enabled | `+++true+++` | Whether to enable Stub Runner integration with Spring Cloud Stream.
|
||||
|stubrunner.stubs-mode | | Pick where the stubs should come from.
|
||||
|stubrunner.stubs-per-consumer | `+++false+++` | Should only stubs for this particular consumer get registered in HTTP server stub.
|
||||
|stubrunner.username | | Repository username.
|
||||
|wiremock.placeholders.enabled | `+++true+++` | Flag to indicate that http URLs in generated wiremock stubs should be filtered to add or resolve a placeholder for a dynamic port.
|
||||
|wiremock.reset-mappings-after-each-test | `+++false+++` |
|
||||
|wiremock.rest-template-ssl-enabled | `+++false+++` |
|
||||
|wiremock.server.files | `+++[]+++` |
|
||||
|wiremock.server.https-port | `+++-1+++` |
|
||||
|wiremock.server.https-port-dynamic | `+++false+++` |
|
||||
|wiremock.server.port | `+++8080+++` |
|
||||
|wiremock.server.port-dynamic | `+++false+++` |
|
||||
|wiremock.server.stubs | `+++[]+++` |
|
||||
|
||||
|===
|
||||
@@ -1,18 +0,0 @@
|
||||
[[spring-cloud-contract-reference-documentation]]
|
||||
= Spring Cloud Contract Reference Documentation
|
||||
Adam Dudczak, Mathias Düsterhöft, Marcin Grzejszczak, Dennis Kieselhorst, Jakub Kubryński, Karol Lassak, Olga Maciaszek-Sharma, Mariusz Smykuła, Dave Syer, Jay Bryant
|
||||
|
||||
:docinfo: shared
|
||||
include::_attributes.adoc[]
|
||||
|
||||
The reference documentation consists of the following sections:
|
||||
|
||||
[horizontal]
|
||||
<<legal.adoc#legal-information,Legal>> :: Legal information.
|
||||
<<documentation-overview.adoc#contract-documentation,Documentation Overview>> :: About the Documentation, Getting Help, First Steps, and more.
|
||||
<<getting-started.adoc#getting-started,Getting Started>> :: Introducing {project-full-name}, Developing Your First {project-full-name}-based Application
|
||||
<<using.adoc#using,Using {project-full-name}>> :: {project-full-name} usage examples and workflows.
|
||||
<<project-features.adoc#features,{project-full-name} Features>> :: Contract DSL, Messaging, Spring Cloud Contract Stub Runner, and Spring Cloud Contract WireMock.
|
||||
<<project-features.adoc#features-build-tools,Build Tools>> :: Maven Plugin, Gradle Plugin, and Docker.
|
||||
<<howto.adoc#howto,"`How-to`" Guides>> :: Stubs versioning, Debugging, and more.
|
||||
<<appendix.adoc#appendix,Appendices>> :: Properties, Metadata, Configuration, Dependencies, and more.
|
||||
@@ -1,16 +0,0 @@
|
||||
[[spring-cloud-contract-reference-documentation]]
|
||||
= Spring Cloud Contract Reference Documentation
|
||||
Adam Dudczak, Mathias Düsterhöft, Marcin Grzejszczak, Dennis Kieselhorst, Jakub Kubryński, Karol Lassak, Olga Maciaszek-Sharma, Mariusz Smykuła, Dave Syer, Jay Bryant
|
||||
|
||||
include::_attributes.adoc[]
|
||||
|
||||
include::legal.adoc[leveloffset=+1]
|
||||
include::getting-started.adoc[leveloffset=+1]
|
||||
include::using.adoc[leveloffset=+1]
|
||||
include::project-features.adoc[leveloffset=+1]
|
||||
include::maven-project.adoc[leveloffset=+1]
|
||||
include::gradle-project.adoc[leveloffset=+1]
|
||||
include::docker-project.adoc[leveloffset=+1]
|
||||
include::advanced.adoc[leveloffset=+1]
|
||||
include::howto.adoc[leveloffset=+1]
|
||||
include::appendix.adoc[leveloffset=+1]
|
||||
@@ -1,17 +0,0 @@
|
||||
[[spring-cloud-contract-reference-documentation]]
|
||||
= Spring Cloud Contract Reference Documentation
|
||||
Adam Dudczak, Mathias Düsterhöft, Marcin Grzejszczak, Dennis Kieselhorst, Jakub Kubryński, Karol Lassak, Olga Maciaszek-Sharma, Mariusz Smykuła, Dave Syer, Jay Bryant
|
||||
|
||||
:docinfo: shared
|
||||
include::_attributes.adoc[]
|
||||
|
||||
include::legal.adoc[leveloffset=+1]
|
||||
include::getting-started.adoc[leveloffset=+1]
|
||||
include::using.adoc[leveloffset=+1]
|
||||
include::project-features.adoc[leveloffset=+1]
|
||||
include::maven-project.adoc[leveloffset=+1]
|
||||
include::gradle-project.adoc[leveloffset=+1]
|
||||
include::docker-project.adoc[leveloffset=+1]
|
||||
include::advanced.adoc[leveloffset=+1]
|
||||
include::howto.adoc[leveloffset=+1]
|
||||
include::appendix.adoc[leveloffset=+1]
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,621 +0,0 @@
|
||||
[[features-messaging]]
|
||||
== Messaging
|
||||
include::_attributes.adoc[]
|
||||
|
||||
Spring Cloud Contract lets you verify applications that use messaging as a
|
||||
means of communication. All of the integrations shown in this document work with Spring,
|
||||
but you can also create one of your own and use that.
|
||||
|
||||
[[contract-dsl-messaging-top-level]]
|
||||
=== Messaging DSL Top-level Elements
|
||||
|
||||
The DSL for messaging looks a little bit different than the one that focuses on HTTP. The
|
||||
following sections explain the differences:
|
||||
|
||||
* <<contract-dsl-output-triggered-method>>
|
||||
* <<contract-dsl-consumer-producer>>
|
||||
* <<contract-dsl-messaging-common>>
|
||||
|
||||
[[contract-dsl-output-triggered-method]]
|
||||
==== Output Triggered by a Method
|
||||
|
||||
The output message can be triggered by calling a method (such as a `Scheduler` when a contract was
|
||||
started and when a message was sent), as shown in the following example:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Groovy
|
||||
----
|
||||
include::{tests_path}/samples-messaging-integration/src/test/groovy/com/example/IntegrationMessagingApplicationSpec.groovy[tags=method_trigger,indent=0]
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.YAML
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract_message_method.yml[indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
In the previous example case, the output message is sent to `output` if a method called
|
||||
`bookReturnedTriggered` is invoked. On the message publisher's side, we generate a
|
||||
test that calls that method to trigger the message. On the consumer side, you can use
|
||||
`some_label` to trigger the message.
|
||||
|
||||
|
||||
[[contract-dsl-consumer-producer]]
|
||||
==== Consumer/Producer
|
||||
|
||||
IMPORTANT: This section is valid only for the Groovy DSL.
|
||||
|
||||
In HTTP, you have a notion of `client`/`stub and `server`/`test` notation. You can also
|
||||
use those paradigms in messaging. In addition, Spring Cloud Contract Verifier also
|
||||
provides the `consumer` and `producer` methods
|
||||
(note that you can use either `$` or `value` methods to provide `consumer` and `producer`
|
||||
parts).
|
||||
|
||||
[[contract-dsl-messaging-common]]
|
||||
==== Common
|
||||
|
||||
In the `input` or `outputMessage` section, you can call `assertThat` with the name
|
||||
of a `method` (for example, `assertThatMessageIsOnTheQueue()`) that you have defined in the
|
||||
base class or in a static import. Spring Cloud Contract runs that method
|
||||
in the generated test.
|
||||
|
||||
[[features-messaging-integrations]]
|
||||
=== Integrations
|
||||
|
||||
You can use one of the following integration configurations:
|
||||
|
||||
* Apache Camel
|
||||
* Spring Integration
|
||||
* Spring Cloud Stream
|
||||
* Spring JMS
|
||||
|
||||
Since we use Spring Boot, if you have added one of these libraries to the classpath, all
|
||||
the messaging configuration is automatically set up.
|
||||
|
||||
IMPORTANT: Remember to put `@AutoConfigureMessageVerifier` on the base class of your
|
||||
generated tests. Otherwise, the messaging part of Spring Cloud Contract does not
|
||||
work.
|
||||
|
||||
[IMPORTANT]
|
||||
=====
|
||||
If you want to use Spring Cloud Stream, remember to add a test dependency on
|
||||
`org.springframework.cloud:spring-cloud-stream`, as follows:
|
||||
|
||||
====
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-stream</artifactId>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
<classifier>test-binder</classifier>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
testImplementation(group: 'org.springframework.cloud', name: 'spring-cloud-stream', classifier: 'test-binder')
|
||||
----
|
||||
====
|
||||
=====
|
||||
|
||||
[[features-messaging-manual]]
|
||||
==== Manual Integration Testing
|
||||
|
||||
The main interface used by the tests is
|
||||
`org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender` and `org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver`.
|
||||
It defines how to send and receive messages.
|
||||
|
||||
In a test, you can inject a `ContractVerifierMessageExchange` to send and receive
|
||||
messages that follow the contract. Then add `@AutoConfigureMessageVerifier` to your test.
|
||||
The following example shows how to do so:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@RunWith(SpringTestRunner.class)
|
||||
@SpringBootTest
|
||||
@AutoConfigureMessageVerifier
|
||||
public static class MessagingContractTests {
|
||||
|
||||
@Autowired
|
||||
private MessageVerifier verifier;
|
||||
...
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: If your tests require stubs as well, then `@AutoConfigureStubRunner` includes the
|
||||
messaging configuration, so you only need the one annotation.
|
||||
|
||||
[[features-messaging-test-generation]]
|
||||
=== Producer Side Messaging Test Generation
|
||||
|
||||
Having the `input` or `outputMessage` sections in your DSL results in creation of tests
|
||||
on the publisher's side. By default, JUnit 4 tests are created. However, there is also a
|
||||
possibility to create JUnit 5, TestNG, or Spock tests.
|
||||
|
||||
IMPORTANT: The destination passed to `messageFrom` or `sentTo` can have different
|
||||
meanings for different messaging implementations. For Stream and Integration, it is
|
||||
first resolved as a `destination` of a channel. Then, if there is no such `destination`,
|
||||
it is resolved as a channel name. For Camel, that's a certain component (for example,
|
||||
`jms`).
|
||||
|
||||
Consider the following contract:
|
||||
|
||||
=====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Groovy
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=trigger_method_dsl]
|
||||
----
|
||||
|
||||
[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract_message_scenario1.yml[indent=0]
|
||||
----
|
||||
=====
|
||||
|
||||
For the preceding example, the following test would be created:
|
||||
|
||||
====
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.JUnit
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=trigger_method_junit_test]
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Spock
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=trigger_method_test]
|
||||
----
|
||||
====
|
||||
|
||||
[[features-messaging-consumer]]
|
||||
=== Consumer Stub Generation
|
||||
|
||||
Unlike in the HTTP part, in messaging, we need to publish the contract definition inside the JAR with
|
||||
a stub. Then it is parsed on the consumer side, and proper stubbed routes are created.
|
||||
|
||||
IMPORTANT: If you have multiple frameworks on the classpath, Stub Runner needs to
|
||||
define which one should be used. Assume that you have AMQP, Spring Cloud Stream, and Spring Integration
|
||||
on the classpath and that you want to use Spring AMQP. Then you need to set
|
||||
`stubrunner.stream.enabled=false` and `stubrunner.integration.enabled=false`.
|
||||
That way, the only remaining framework is Spring AMQP.
|
||||
|
||||
[[features-messaging-stub-triggering]]
|
||||
==== Stub triggering
|
||||
|
||||
To trigger a message, use the `StubTrigger` interface, as the following example shows:
|
||||
|
||||
====
|
||||
[source,groovy]
|
||||
----
|
||||
include::{stubrunner_core_path}/src/main/java/org/springframework/cloud/contract/stubrunner/StubTrigger.java[lines=16..-1]
|
||||
----
|
||||
====
|
||||
|
||||
For convenience, the `StubFinder` interface extends `StubTrigger`, so you need only one
|
||||
or the other in your tests.
|
||||
|
||||
`StubTrigger` gives you the following options to trigger a message:
|
||||
|
||||
* <<features-messaging-trigger-label>>
|
||||
* <<features-messaging-trigger-group-artifact-ids>>
|
||||
* <<features-messaging-trigger-artifact-ids>>
|
||||
* <<features-messaging-trigger-all-messages>>
|
||||
|
||||
[[features-messaging-trigger-label]]
|
||||
==== Trigger by Label
|
||||
|
||||
The following example shows how to trigger a message with a label:
|
||||
|
||||
====
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=client_trigger,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
[[features-messaging-trigger-group-artifact-ids]]
|
||||
==== Trigger by Group and Artifact IDs
|
||||
|
||||
The following example shows how to trigger a message by group and artifact IDs:
|
||||
|
||||
====
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=trigger_group_artifact,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
[[features-messaging-trigger-artifact-ids]]
|
||||
==== Trigger by Artifact IDs
|
||||
|
||||
The following example shows how to trigger a message from artifact IDs:
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=trigger_artifact,indent=0]
|
||||
----
|
||||
|
||||
[[features-messaging-trigger-all-messages]]
|
||||
==== Trigger All Messages
|
||||
|
||||
The following example shows how to trigger all messages:
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=trigger_all,indent=0]
|
||||
----
|
||||
|
||||
:input_name: jms:input
|
||||
:output_name: jms:output
|
||||
|
||||
[[features-messaging-stub-runner-camel]]
|
||||
=== Consumer Side Messaging With Apache Camel
|
||||
|
||||
Spring Cloud Contract Stub Runner's messaging module gives you an easy way to integrate with Apache Camel.
|
||||
For the provided artifacts, it automatically downloads the stubs and registers the required
|
||||
routes.
|
||||
|
||||
[[features-messaging-stub-runner-camel-adding]]
|
||||
==== Adding Apache Camel to the Project
|
||||
|
||||
You can have both Apache Camel and Spring Cloud Contract Stub Runner on the classpath.
|
||||
Remember to annotate your test class with `@AutoConfigureStubRunner`.
|
||||
|
||||
[[features-messaging-stub-runner-camel-disabling]]
|
||||
==== Disabling the Functionality
|
||||
|
||||
If you need to disable this functionality, set the `stubrunner.camel.enabled=false` property.
|
||||
|
||||
[[features-messaging-stub-runner-camel-example]]
|
||||
==== Examples
|
||||
|
||||
Assume that we have the following Maven repository with deployed stubs for the
|
||||
`camelService` application:
|
||||
|
||||
====
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
└── .m2
|
||||
└── repository
|
||||
└── io
|
||||
└── codearte
|
||||
└── accurest
|
||||
└── stubs
|
||||
└── camelService
|
||||
├── 0.0.1-SNAPSHOT
|
||||
│ ├── camelService-0.0.1-SNAPSHOT.pom
|
||||
│ ├── camelService-0.0.1-SNAPSHOT-stubs.jar
|
||||
│ └── maven-metadata-local.xml
|
||||
└── maven-metadata-local.xml
|
||||
----
|
||||
====
|
||||
|
||||
Further, assume that the stubs contain the following structure:
|
||||
|
||||
====
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
├── META-INF
|
||||
│ └── MANIFEST.MF
|
||||
└── repository
|
||||
├── accurest
|
||||
│ └── bookReturned1.groovy
|
||||
└── mappings
|
||||
----
|
||||
====
|
||||
|
||||
Now consider the following contract:
|
||||
|
||||
====
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/samples-messaging-camel/src/test/groovy/com/example/CamelMessagingApplicationSpec.groovy[tags=sample_dsl,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
To trigger a message from the `return_book_1` label, we use the `StubTrigger` interface, as follows:
|
||||
|
||||
====
|
||||
[source,groovy]
|
||||
----
|
||||
stubFinder.trigger("return_book_1")
|
||||
----
|
||||
====
|
||||
|
||||
That will send out a message to the destination described in the output message of the contract.
|
||||
|
||||
:input_name: input
|
||||
:output_name: output
|
||||
|
||||
[[features-messaging-stub-runner-integration]]
|
||||
=== Consumer Side Messaging with Spring Integration
|
||||
|
||||
Spring Cloud Contract Stub Runner's messaging module gives you an easy way to
|
||||
integrate with Spring Integration. For the provided artifacts, it automatically downloads
|
||||
the stubs and registers the required routes.
|
||||
|
||||
[[features-messaging-stub-runner-integration-adding]]
|
||||
==== Adding the Runner to the Project
|
||||
|
||||
You can have both Spring Integration and Spring Cloud Contract Stub Runner on the
|
||||
classpath. Remember to annotate your test class with `@AutoConfigureStubRunner`.
|
||||
|
||||
[[features-messaging-stub-runner-integration-disabling]]
|
||||
==== Disabling the Functionality
|
||||
|
||||
If you need to disable this functionality, set the
|
||||
`stubrunner.integration.enabled=false` property.
|
||||
|
||||
[[features-messaging-stub-runner-integration-example]]
|
||||
==== Examples
|
||||
|
||||
Assume that you have the following Maven repository with deployed stubs for the
|
||||
`integrationService` application:
|
||||
|
||||
====
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
└── .m2
|
||||
└── repository
|
||||
└── io
|
||||
└── codearte
|
||||
└── accurest
|
||||
└── stubs
|
||||
└── integrationService
|
||||
├── 0.0.1-SNAPSHOT
|
||||
│ ├── integrationService-0.0.1-SNAPSHOT.pom
|
||||
│ ├── integrationService-0.0.1-SNAPSHOT-stubs.jar
|
||||
│ └── maven-metadata-local.xml
|
||||
└── maven-metadata-local.xml
|
||||
----
|
||||
====
|
||||
|
||||
Further assume the stubs contain the following structure:
|
||||
|
||||
====
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
├── META-INF
|
||||
│ └── MANIFEST.MF
|
||||
└── repository
|
||||
├── accurest
|
||||
│ └── bookReturned1.groovy
|
||||
└── mappings
|
||||
----
|
||||
====
|
||||
|
||||
Consider the following contract:
|
||||
|
||||
====
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy[tags=sample_dsl,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
Now consider the following Spring Integration Route:
|
||||
|
||||
====
|
||||
[source,xml]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-integration/src/test/resources/integration-context.xml[lines=1;18..-1]
|
||||
----
|
||||
====
|
||||
|
||||
To trigger a message from the `return_book_1` label, use the `StubTrigger` interface, as
|
||||
follows:
|
||||
|
||||
====
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy[tags=client_trigger,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
That will send out a message to the destination described in the output message of the contract.
|
||||
|
||||
[[features-messaging-stub-runner-stream]]
|
||||
=== Consumer Side Messaging With Spring Cloud Stream
|
||||
|
||||
Spring Cloud Contract Stub Runner's messaging module gives you an easy way to
|
||||
integrate with Spring Stream. For the provided artifacts, it automatically downloads the
|
||||
stubs and registers the required routes.
|
||||
|
||||
CAUTION: If Stub Runner's integration with the Stream `messageFrom` or `sentTo` strings
|
||||
are resolved first as the `destination` of a channel and no such `destination` exists, the
|
||||
destination is resolved as a channel name.
|
||||
|
||||
[IMPORTANT]
|
||||
=====
|
||||
If you want to use Spring Cloud Stream, remember to add a dependency on
|
||||
`org.springframework.cloud:spring-cloud-stream` test support, as follows:
|
||||
|
||||
====
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-stream-test-binder</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
testImplementation('org.springframework.cloud:spring-cloud-stream-test-binder')
|
||||
----
|
||||
====
|
||||
=====
|
||||
|
||||
[[features-messaging-stub-runner-stream-adding]]
|
||||
==== Adding the Runner to the Project
|
||||
|
||||
You can have both Spring Cloud Stream and Spring Cloud Contract Stub Runner on the
|
||||
classpath. Remember to annotate your test class with `@AutoConfigureStubRunner`.
|
||||
|
||||
[[features-messaging-stub-runner-stream-disabling]]
|
||||
==== Disabling the Functionality
|
||||
|
||||
If you need to disable this functionality, set the `stubrunner.stream.enabled=false`
|
||||
property.
|
||||
|
||||
[[features-messaging-stub-runner-stream-example]]
|
||||
==== Examples
|
||||
|
||||
Assume that you have the following Maven repository with deployed stubs for the
|
||||
`streamService` application:
|
||||
|
||||
====
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
└── .m2
|
||||
└── repository
|
||||
└── io
|
||||
└── codearte
|
||||
└── accurest
|
||||
└── stubs
|
||||
└── streamService
|
||||
├── 0.0.1-SNAPSHOT
|
||||
│ ├── streamService-0.0.1-SNAPSHOT.pom
|
||||
│ ├── streamService-0.0.1-SNAPSHOT-stubs.jar
|
||||
│ └── maven-metadata-local.xml
|
||||
└── maven-metadata-local.xml
|
||||
----
|
||||
====
|
||||
|
||||
Further assume the stubs contain the following structure:
|
||||
|
||||
====
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
├── META-INF
|
||||
│ └── MANIFEST.MF
|
||||
└── repository
|
||||
├── accurest
|
||||
│ └── bookReturned1.groovy
|
||||
└── mappings
|
||||
----
|
||||
====
|
||||
|
||||
Consider the following contract:
|
||||
|
||||
====
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=sample_dsl,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
Now consider the following Spring Cloud Stream function configuration:
|
||||
|
||||
====
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=setup,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
Now consider the following Spring configuration:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/resources/application.yml[]
|
||||
----
|
||||
====
|
||||
|
||||
To trigger a message from the `return_book_1` label, use the `StubTrigger` interface as
|
||||
follows:
|
||||
|
||||
====
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=client_trigger,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
That will send out a message to the destination described in the output message of the contract.
|
||||
|
||||
[[features-messaging-stub-runner-jms]]
|
||||
=== Consumer Side Messaging With Spring JMS
|
||||
|
||||
Spring Cloud Contract Stub Runner's messaging module provides an easy way to
|
||||
integrate with Spring JMS.
|
||||
|
||||
The integration assumes that you have a running instance of a JMS broker.
|
||||
|
||||
[[features-messaging-stub-runner-jms-adding]]
|
||||
==== Adding the Runner to the Project
|
||||
|
||||
You need to have both Spring JMS and Spring Cloud Contract Stub Runner on the classpath. Remember to annotate your test class
|
||||
with `@AutoConfigureStubRunner`.
|
||||
|
||||
:input_name: input
|
||||
:output_name: output
|
||||
|
||||
[[features-messaging-stub-runner-jms-example]]
|
||||
==== Examples
|
||||
|
||||
Assume that the stub structure looks as follows:
|
||||
|
||||
====
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
├── stubs
|
||||
└── bookReturned1.groovy
|
||||
|
||||
----
|
||||
====
|
||||
|
||||
Further assume the following test configuration:
|
||||
|
||||
====
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
stubrunner:
|
||||
repository-root: stubs:classpath:/stubs/
|
||||
ids: my:stubs
|
||||
stubs-mode: remote
|
||||
spring:
|
||||
activemq:
|
||||
send-timeout: 1000
|
||||
jms:
|
||||
template:
|
||||
receive-timeout: 1000
|
||||
----
|
||||
====
|
||||
|
||||
Now consider the following contract:
|
||||
|
||||
====
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-jms/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/jms/JmsStubRunnerSpec.groovy[tags=sample_dsl,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
To trigger a message from the `return_book_1` label, we use the `StubTrigger` interface, as follows:
|
||||
|
||||
====
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-jms/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/jms/JmsStubRunnerSpec.groovy[tags=client_trigger,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
That will send out a message to the destination described in the output message of the contract.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,201 +0,0 @@
|
||||
[[features-wiremock]]
|
||||
== Spring Cloud Contract WireMock
|
||||
include::_attributes.adoc[]
|
||||
|
||||
The Spring Cloud Contract WireMock modules let you use https://github.com/tomakehurst/wiremock[WireMock] in a
|
||||
Spring Boot application. For more detail, check out the
|
||||
https://github.com/spring-cloud/spring-cloud-contract/tree/{github-tag}/samples[samples].
|
||||
|
||||
If you have a Spring Boot application that uses Tomcat as an embedded server (which is
|
||||
the default with `spring-boot-starter-web`), you can add
|
||||
`spring-cloud-starter-contract-stub-runner` to your classpath and add `@AutoConfigureWireMock`
|
||||
to use Wiremock in your tests. Wiremock runs as a stub server, and you
|
||||
can register stub behavior by using a Java API or by using static JSON declarations as part of
|
||||
your test. The following code shows an example:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{doc_samples_url}/src/test/java/com/example/WiremockForDocsTests.java[tags=wiremock_test1]
|
||||
include::{doc_samples_url}/src/test/java/com/example/WiremockForDocsTests.java[tags=wiremock_test2]
|
||||
----
|
||||
====
|
||||
|
||||
To start the stub server on a different port, use (for example),
|
||||
`@AutoConfigureWireMock(port=9999)`. For a random port, use a value of `0`. The stub
|
||||
server port can be bound in the test application context with the `wiremock.server.port`
|
||||
property. Using `@AutoConfigureWireMock` adds a bean of type `WiremockConfiguration` to
|
||||
your test application context, where it is cached between methods and classes
|
||||
that have the same context. The same is true for Spring integration tests. Also, you can
|
||||
inject a bean of type `WireMockServer` into your test.
|
||||
The registered WireMock server is reset after each test class.
|
||||
However, if you need to reset it after each test method, set the `wiremock.reset-mappings-after-each-test` property to `true`.
|
||||
|
||||
[[features-wiremock-registering-stubs]]
|
||||
=== Registering Stubs Automatically
|
||||
|
||||
If you use `@AutoConfigureWireMock`, it registers WireMock JSON stubs from the file
|
||||
system or classpath (by default, from `file:src/test/resources/mappings`). You can
|
||||
customize the locations by using the `stubs` attribute in the annotation, which can be an
|
||||
Ant-style resource pattern or a directory. In the case of a directory, `**/*.json` is
|
||||
appended. The following code shows an example:
|
||||
|
||||
====
|
||||
----
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
@AutoConfigureWireMock(stubs="classpath:/stubs")
|
||||
public class WiremockImportApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private Service service;
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: Actually, WireMock always loads mappings from `src/test/resources/mappings` *as
|
||||
well as* the custom locations in the `stubs` attribute. To change this behavior, you can
|
||||
also specify a file root, as described in the <<features-wiremock-using-files,next section of this document>>.
|
||||
|
||||
NOTE: Also, the mappings in the `stubs` location are not considered part of Wiremock's "default mappings" and calls
|
||||
to `com.github.tomakehurst.wiremock.client.WireMock.resetToDefaultMappings` during a test do not result in the mappings
|
||||
in the `stubs` location being included. However, the `org.springframework.cloud.contract.wiremock.WireMockTestExecutionListener`
|
||||
does reset the mappings (including adding the ones from the stubs location) after every test class and, optionally,
|
||||
after every test method (guarded by the `wiremock.reset-mappings-after-each-test` property).
|
||||
|
||||
If you use Spring Cloud Contract's default stub jars, your
|
||||
stubs are stored in the `/META-INF/group-id/artifact-id/versions/mappings/` folder.
|
||||
If you want to register all stubs from that location, from all embedded JARs, you can use
|
||||
the following syntax:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{wiremock_tests}/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationWithUrlResourceTests.java[tags=load_all_stubs]
|
||||
----
|
||||
====
|
||||
|
||||
[[features-wiremock-using-files]]
|
||||
=== Using Files to Specify the Stub Bodies
|
||||
|
||||
WireMock can read response bodies from files on the classpath or the file system. In the
|
||||
case of the file system, you can see in the JSON DSL that the response has a `bodyFileName` instead of a
|
||||
(literal) `body`. The files are resolved relative to a root directory (by default,
|
||||
`src/test/resources/\__files`). To customize this location, you can set the `files`
|
||||
attribute in the `@AutoConfigureWireMock` annotation to the location of the parent
|
||||
directory (in other words, `__files` is a subdirectory). You can use a Spring resource
|
||||
notation to refer to `file:...` or `classpath:...` locations. Generic URLs are not
|
||||
supported. A list of values can be given -- in which case, WireMock resolves the first file
|
||||
that exists when it needs to find a response body.
|
||||
|
||||
NOTE: When you configure the `files` root, it also affects the
|
||||
automatic loading of stubs, because they come from the root location
|
||||
in a subdirectory called `mappings`.
|
||||
|
||||
NOTE: The value of `files` has no
|
||||
effect on the stubs loaded explicitly from the `stubs` attribute.
|
||||
|
||||
[[features-wiremock-junit-rule]]
|
||||
=== Alternative: Using JUnit Rules
|
||||
|
||||
For a more conventional WireMock experience, you can use JUnit `@Rules` to start and stop
|
||||
the server. To do so, use the `WireMockSpring` convenience class to obtain an `Options`
|
||||
instance, as the following example shows:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{doc_samples_url}/src/test/java/com/example/WiremockForDocsClassRuleTests.java[tags=wiremock_test1]
|
||||
include::{doc_samples_url}/src/test/java/com/example/WiremockForDocsClassRuleTests.java[tags=wiremock_test2]
|
||||
----
|
||||
====
|
||||
|
||||
The `@ClassRule` means that the server shuts down after all the methods in this class
|
||||
have been run.
|
||||
|
||||
[[features-wiremock-relaxed-ssl]]
|
||||
=== Relaxed SSL Validation for Rest Template
|
||||
|
||||
WireMock lets you stub a "`secure`" server with an `https` URL protocol. If your
|
||||
application wants to contact that stub server in an integration test, it finds that
|
||||
the SSL certificates are not valid (the usual problem with self-installed certificates).
|
||||
The best option is often to re-configure the client to use `http`. If that is not an
|
||||
option, you can ask Spring to configure an HTTP client that ignores SSL validation errors
|
||||
(do so only for tests, of course).
|
||||
|
||||
To make this work with minimum fuss, you need to use the Spring Boot
|
||||
`RestTemplateBuilder` in your application, as the following example shows:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@Bean
|
||||
public RestTemplate restTemplate(RestTemplateBuilder builder) {
|
||||
return builder.build();
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
You need `RestTemplateBuilder` because the builder is passed through callbacks to
|
||||
initialize it, so the SSL validation can be set up in the client at that point. This
|
||||
happens automatically in your test if you use the `@AutoConfigureWireMock`
|
||||
annotation or the stub runner. If you use the JUnit `@Rule` approach, you need to add the
|
||||
`@AutoConfigureHttpClient` annotation as well, as the following example shows:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest("app.baseUrl=https://localhost:6443")
|
||||
@AutoConfigureHttpClient
|
||||
public class WiremockHttpsServerApplicationTests {
|
||||
|
||||
@ClassRule
|
||||
public static WireMockClassRule wiremock = new WireMockClassRule(
|
||||
WireMockSpring.options().httpsPort(6443));
|
||||
...
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
If you use `spring-boot-starter-test`, you have the Apache HTTP client on the
|
||||
classpath, and it is selected by the `RestTemplateBuilder` and configured to ignore SSL
|
||||
errors. If you use the default `java.net` client, you do not need the annotation (but it
|
||||
does no harm). There is currently no support for other clients, but it may be added
|
||||
in future releases.
|
||||
|
||||
To disable the custom `RestTemplateBuilder`, set the `wiremock.rest-template-ssl-enabled`
|
||||
property to `false`.
|
||||
|
||||
[[features-wiremock-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`. The following code shows an example:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{doc_samples_url}/src/test/java/com/example/WiremockForDocsMockServerApplicationTests.java[tags=wiremock_test]
|
||||
----
|
||||
====
|
||||
|
||||
The `baseUrl` value is prepended to all mock calls, and the `stubs()` method takes a stub
|
||||
path resource pattern as an argument. In the preceding example, the stub defined at
|
||||
`/stubs/resource.json` is loaded into the mock server. If the `RestTemplate` is asked to
|
||||
visit `https://example.org/`, it gets the responses as being declared at that URL. More
|
||||
than one stub pattern can be specified, and each one can be a directory (for a recursive
|
||||
list of all `.json`), a fixed filename (as in the preceding example), or an Ant-style
|
||||
pattern. The JSON format is the normal WireMock format, which you can read about at the
|
||||
https://wiremock.org/docs/stubbing/[WireMock website].
|
||||
|
||||
Currently, the Spring Cloud Contract Verifier supports Tomcat, Jetty, and Undertow as
|
||||
Spring Boot embedded servers, and Wiremock itself has "`native`" support for a 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).
|
||||
@@ -1,463 +0,0 @@
|
||||
[[contract-customization]]
|
||||
= Spring Cloud Contract customization
|
||||
include::_attributes.adoc[]
|
||||
|
||||
In this section, we describe how to customize various parts of Spring Cloud Contract.
|
||||
|
||||
[[customization-customization]]
|
||||
== DSL Customization
|
||||
|
||||
IMPORTANT: This section is valid only for the Groovy DSL
|
||||
|
||||
You can customize the Spring Cloud Contract Verifier by extending the DSL, as shown in
|
||||
the remainder of this section.
|
||||
|
||||
[[customization-extending]]
|
||||
=== Extending the DSL
|
||||
|
||||
You can provide your own functions to the DSL. The key requirement for this feature is to
|
||||
maintain the static compatibility. Later in this chapter, you can see examples of:
|
||||
|
||||
* Creating a JAR with reusable classes.
|
||||
* Referencing of these classes in the DSLs.
|
||||
|
||||
You can find the full example
|
||||
https://github.com/spring-cloud-samples/spring-cloud-contract-samples[here].
|
||||
|
||||
[[customization-extending-common-jar]]
|
||||
=== Common JAR
|
||||
|
||||
The following examples show three classes that can be reused in the DSLs.
|
||||
|
||||
`PatternUtils` contains functions used by both the consumer and the producer.
|
||||
The following listing shows the `PatternUtils` class:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{samples_url}/common/src/main/java/com/example/PatternUtils.java[]
|
||||
----
|
||||
====
|
||||
|
||||
`ConsumerUtils` contains functions used by the consumer.
|
||||
The following listing shows the `ConsumerUtils` class:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{samples_url}/common/src/main/java/com/example/ConsumerUtils.java[]
|
||||
----
|
||||
====
|
||||
|
||||
`ProducerUtils` contains functions used by the producer.
|
||||
The following listing shows the `ProducerUtils` class:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{samples_url}/common/src/main/java/com/example/ProducerUtils.java[]
|
||||
----
|
||||
====
|
||||
|
||||
[[customization-test-dep]]
|
||||
=== Adding a Test Dependency in the Project's Dependencies
|
||||
|
||||
To add a test dependency in the project's dependencies, you must first add the common jar
|
||||
dependency as a test dependency. Because your contracts files
|
||||
are available on the test resources path, the common jar classes automatically become
|
||||
visible in your Groovy files. The following examples show how to test the dependency:
|
||||
|
||||
====
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
include::{samples_url}/producer/pom.xml[tags=test_dep,indent=0]
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
include::{samples_url}/producer/build.gradle[tags=test_dep,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
[[customization-plugin-dep]]
|
||||
=== Adding a Test Dependency in the Plugin's Dependencies
|
||||
|
||||
Now, you must add the dependency for the plugin to reuse at runtime, as the
|
||||
following example shows:
|
||||
|
||||
====
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
include::{samples_url}/producer/pom.xml[tags=test_dep_in_plugin,indent=0]
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
include::{samples_url}/producer/build.gradle[tags=test_dep_in_plugin,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
[[customization-referencing]]
|
||||
=== Referencing Classes in DSLs
|
||||
|
||||
You can now reference your classes in your DSL, as the following example shows:
|
||||
|
||||
====
|
||||
[source,groovy]
|
||||
----
|
||||
include::{samples_url}/producer/src/test/resources/contracts/beer/rest/shouldGrantABeerIfOldEnough.groovy[indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
IMPORTANT: You can set the Spring Cloud Contract plugin up by setting `convertToYaml` to
|
||||
`true`. That way, you do NOT have to add the dependency with the extended functionality
|
||||
to the consumer side, since the consumer side uses YAML contracts instead of Groovy contracts.
|
||||
|
||||
[[customization-wiremock]]
|
||||
== WireMock Customization
|
||||
|
||||
In this section, we show how to customize the way you work with https://wiremock.org[WireMock].
|
||||
|
||||
[[customization-wiremock-extension]]
|
||||
=== Registering Your Own WireMock Extension
|
||||
|
||||
WireMock lets you register custom extensions. By default, Spring Cloud Contract registers
|
||||
the transformer, which lets you reference a request from a response. If you want to
|
||||
provide your own extensions, you can register an implementation of the
|
||||
`org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockExtensions` interface.
|
||||
Since we use the `spring.factories` extension approach, you can create an entry similar to
|
||||
the following in the `META-INF/spring.factories` file:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{stubrunner_core_path}/src/test/resources/META-INF/spring.factories[indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
The following example shows a custom extension:
|
||||
|
||||
.TestWireMockExtensions.groovy
|
||||
====
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/TestWireMockExtensions.groovy[indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
IMPORTANT: If you want the transformation to be applied only for a mapping that explicitly
|
||||
requires it, override the `applyGlobally()` method and set it to `false` .
|
||||
|
||||
[[customization-wiremock-configuration]]
|
||||
=== Customization of WireMock Configuration
|
||||
|
||||
You can register a bean of type `org.springframework.cloud.contract.wiremock.WireMockConfigurationCustomizer`
|
||||
to customize the WireMock configuration (for example, to add custom transformers).
|
||||
The following example shows how to do so:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{wiremock_tests}/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockConfigurationCustomizerTests.java[tags=customizer_1]
|
||||
// perform your customization here
|
||||
include::{wiremock_tests}/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockConfigurationCustomizerTests.java[tags=customizer_2]
|
||||
----
|
||||
====
|
||||
|
||||
[[customization-wiremock-from-metadata]]
|
||||
=== Customization of WireMock via Metadata
|
||||
|
||||
With version 3.0.0 you're able to set `metadata` in your contracts. If you set an entry with key equal to `wiremock` and the value
|
||||
will be a valid WireMock's `StubMapping` JSON / map or an actual `StubMapping` object, Spring Cloud Contract will patch the generated
|
||||
stub with part of your customization. Let's look at the following example
|
||||
|
||||
[source,yaml,indent=0]
|
||||
----
|
||||
include::{standalone_samples_path}/http-server/src/test/resources/contracts/yml/fraud/shouldReturnFraudStats.yml[tags=metadata,indent=0]
|
||||
----
|
||||
|
||||
In the `metadata` section we've set an entry with key `wiremock` and its value is a JSON `StubMapping` that sets a delay in the generated stub. Such code allowed us to get the following merged WireMock JSON stub.
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"id" : "ebae49e2-a2a3-490c-a57f-ba28e26b81ea",
|
||||
"request" : {
|
||||
"url" : "/yamlfrauds",
|
||||
"method" : "GET"
|
||||
},
|
||||
"response" : {
|
||||
"status" : 200,
|
||||
"body" : "{\"count\":200}",
|
||||
"headers" : {
|
||||
"Content-Type" : "application/json"
|
||||
},
|
||||
"fixedDelayMilliseconds" : 2000,
|
||||
"transformers" : [ "response-template" ]
|
||||
},
|
||||
"uuid" : "ebae49e2-a2a3-490c-a57f-ba28e26b81ea"
|
||||
}
|
||||
----
|
||||
|
||||
The current implementation allows to manipulate only the stub side (we don't change the generated test). Also, what does not get changed
|
||||
are the whole request and body and headers of the response.
|
||||
|
||||
[[customization-wiremock-from-metadata-custom-processor]]
|
||||
==== Customization of WireMock via Metadata and a Custom Processor
|
||||
|
||||
If you want to apply a custom WireMock `StubMapping` post processing, you can under `META-INF/spring.factories` under the
|
||||
`org.springframework.cloud.contract.verifier.converter.StubProcessor` key register your own implementation of a stub processor. For your convenience we've created an interface called `org.springframework.cloud.contract.verifier.wiremock.WireMockStubPostProcessor` that is dedicated to WireMock.
|
||||
|
||||
You'll have to implement methods to inform Spring Cloud Contract whether the post processor is applicable for a given contract and how should the post processing look like.
|
||||
|
||||
IMPORTANT: On the consumer side, when using Stub Runner, remember to pass the custom `HttpServerStubConfigurer` implementation (e.g. the one that extends `WireMockHttpServerStubConfigurer`) where you'll register a custom extension of your choosing. If you don't do so, even you have a custom WireMock extension on the classpath, WireMock will not notice it, won't apply it and will print out a warning statement that the given extension was not found.
|
||||
|
||||
[[customization-pluggable-architecture]]
|
||||
== Using the Pluggable Architecture
|
||||
|
||||
You may encounter cases where your contracts have been defined in other formats,
|
||||
such as YAML, RAML, or PACT. In those cases, you still want to benefit from the automatic
|
||||
generation of tests and stubs. You can add your own implementation for generating both
|
||||
tests and stubs. Also, you can customize the way tests are generated (for example, you
|
||||
can generate tests for other languages) and the way stubs are generated (for example, you
|
||||
can generate stubs for other HTTP server implementations).
|
||||
|
||||
[[customization-custom-contract-converter]]
|
||||
=== Custom Contract Converter
|
||||
|
||||
The `ContractConverter` interface lets you register your own implementation of a contract
|
||||
structure converter. The following code listing shows the `ContractConverter` interface:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{contract_spec_path}/src/main/java/org/springframework/cloud/contract/spec/ContractConverter.java[indent=0,lines=17..-1]
|
||||
----
|
||||
====
|
||||
|
||||
Your implementation must define the condition on which it should start the
|
||||
conversion. Also, you must define how to perform that conversion in both directions.
|
||||
|
||||
IMPORTANT: Once you create your implementation, you must create a
|
||||
`/META-INF/spring.factories` file in which you provide the fully qualified name of your
|
||||
implementation.
|
||||
|
||||
The following example shows a typical `spring.factories` file:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
org.springframework.cloud.contract.spec.ContractConverter=\
|
||||
org.springframework.cloud.contract.verifier.converter.YamlContractConverter
|
||||
----
|
||||
====
|
||||
|
||||
[[customization-custom-test-generator]]
|
||||
=== Using the Custom Test Generator
|
||||
|
||||
If you want to generate tests for languages other than Java or you are not happy with the
|
||||
way the verifier builds Java tests, you can register your own implementation.
|
||||
|
||||
The `SingleTestGenerator` interface lets you register your own implementation. The
|
||||
following code listing shows the `SingleTestGenerator` interface:
|
||||
|
||||
====
|
||||
[source,groovy]
|
||||
----
|
||||
include::{verifier_core_path}/src/main/java/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.java[indent=0,lines=17..-1]
|
||||
----
|
||||
====
|
||||
|
||||
Again, you must provide a `spring.factories` file, such as the one shown in the following
|
||||
example:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
org.springframework.cloud.contract.verifier.builder.SingleTestGenerator=/
|
||||
com.example.MyGenerator
|
||||
----
|
||||
====
|
||||
|
||||
[[customization-custom-stub-generator]]
|
||||
=== Using the Custom Stub Generator
|
||||
|
||||
If you want to generate stubs for stub servers other than WireMock, you can plug in your
|
||||
own implementation of the `StubGenerator` interface. The following code listing shows the
|
||||
`StubGenerator` interface:
|
||||
|
||||
====
|
||||
[source,groovy]
|
||||
----
|
||||
include::{converters_path}/src/main/java/org/springframework/cloud/contract/verifier/converter/StubGenerator.java[indent=0,lines=16..-1]
|
||||
----
|
||||
====
|
||||
|
||||
Again, you must provide a `spring.factories` file, such as the one shown in the following
|
||||
example:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
include::{converters_path}/src/main/resources/META-INF/spring.factories[indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
The default implementation is the WireMock stub generation.
|
||||
|
||||
TIP: You can provide multiple stub generator implementations. For example, from a single
|
||||
DSL, you can produce both WireMock stubs and Pact files.
|
||||
|
||||
[[customization-custom-stub-runner]]
|
||||
=== Using the Custom Stub Runner
|
||||
|
||||
If you decide to use custom stub generation, you also need a custom way of running
|
||||
stubs with your different stub provider.
|
||||
|
||||
Assume that you use https://github.com/dreamhead/moco[Moco] to build your stubs and that
|
||||
you have written a stub generator and placed your stubs in a JAR file.
|
||||
|
||||
In order for Stub Runner to know how to run your stubs, you have to define a custom
|
||||
HTTP Stub server implementation, which might resemble the following example:
|
||||
|
||||
====
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-moco/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/moco/MocoHttpServerStub.groovy[indent=0,lines=16..-1]
|
||||
----
|
||||
====
|
||||
|
||||
Then you can register it in your `spring.factories` file, as the following
|
||||
example shows:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
org.springframework.cloud.contract.stubrunner.HttpServerStub=\
|
||||
org.springframework.cloud.contract.stubrunner.provider.moco.MocoHttpServerStub
|
||||
----
|
||||
====
|
||||
|
||||
Now you can run stubs with Moco.
|
||||
|
||||
IMPORTANT: If you do not provide any implementation, the default (WireMock)
|
||||
implementation is used. If you provide more than one, the first one on the list is used.
|
||||
|
||||
[[customization-custom-stub-downloader]]
|
||||
=== Using the Custom Stub Downloader
|
||||
|
||||
You can customize the way your stubs are downloaded by creating an implementation of the
|
||||
`StubDownloaderBuilder` interface, as the following example shows:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
package com.example;
|
||||
|
||||
class CustomStubDownloaderBuilder implements StubDownloaderBuilder {
|
||||
|
||||
@Override
|
||||
public StubDownloader build(final StubRunnerOptions stubRunnerOptions) {
|
||||
return new StubDownloader() {
|
||||
@Override
|
||||
public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
|
||||
StubConfiguration config) {
|
||||
File unpackedStubs = retrieveStubs();
|
||||
return new AbstractMap.SimpleEntry<>(
|
||||
new StubConfiguration(config.getGroupId(), config.getArtifactId(), version,
|
||||
config.getClassifier()), unpackedStubs);
|
||||
}
|
||||
|
||||
File retrieveStubs() {
|
||||
// here goes your custom logic to provide a folder where all the stubs reside
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Then you can register it in your `spring.factories` file, as the following
|
||||
example shows:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
# Example of a custom Stub Downloader Provider
|
||||
org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder=\
|
||||
com.example.CustomStubDownloaderBuilder
|
||||
----
|
||||
====
|
||||
|
||||
Now you can pick a folder with the source of your stubs.
|
||||
|
||||
IMPORTANT: If you do not provide any implementation, the default (scanning the classpath) is used.
|
||||
If you provide the `stubsMode = StubRunnerProperties.StubsMode.LOCAL` or
|
||||
`stubsMode = StubRunnerProperties.StubsMode.REMOTE`, the Aether implementation is used
|
||||
If you provide more than one, the first one on the list is used.
|
||||
|
||||
[[scm-stub-downloader]]
|
||||
=== Using the SCM Stub Downloader
|
||||
|
||||
Whenever the `repositoryRoot` starts with a SCM protocol
|
||||
(currently, we support only `git://`), the stub downloader tries
|
||||
to clone the repository and use it as a source of contracts
|
||||
to generate tests or stubs.
|
||||
|
||||
Through environment variables, system properties, or properties set
|
||||
inside the plugin or the contracts repository configuration, you can
|
||||
tweak the downloader's behavior. The following table describes the available
|
||||
properties:
|
||||
|
||||
.SCM Stub Downloader properties
|
||||
|====
|
||||
|Type of a property |Name of the property | Description
|
||||
|
|
||||
* `git.branch` (plugin prop)
|
||||
|
||||
* `stubrunner.properties.git.branch` (system prop)
|
||||
|
||||
* `STUBRUNNER_PROPERTIES_GIT_BRANCH` (env prop)
|
||||
|master
|
||||
|Which branch to checkout
|
||||
|
||||
|
|
||||
* `git.username` (plugin prop)
|
||||
|
||||
* `stubrunner.properties.git.username` (system prop)
|
||||
|
||||
* `STUBRUNNER_PROPERTIES_GIT_USERNAME` (env prop)
|
||||
|
|
||||
|Git clone username
|
||||
|
||||
|
|
||||
* `git.password` (plugin prop)
|
||||
|
||||
* `stubrunner.properties.git.password` (system prop)
|
||||
|
||||
* `STUBRUNNER_PROPERTIES_GIT_PASSWORD` (env prop)
|
||||
|
|
||||
|Git clone password
|
||||
|
||||
|
|
||||
* `git.no-of-attempts` (plugin prop)
|
||||
|
||||
* `stubrunner.properties.git.no-of-attempts` (system prop)
|
||||
|
||||
* `STUBRUNNER_PROPERTIES_GIT_NO_OF_ATTEMPTS` (env prop)
|
||||
|10
|
||||
|Number of attempts to push the commits to `origin`
|
||||
|
||||
|
|
||||
* `git.wait-between-attempts` (Plugin prop)
|
||||
|
||||
* `stubrunner.properties.git.wait-between-attempts` (system prop)
|
||||
|
||||
* `STUBRUNNER_PROPERTIES_GIT_WAIT_BETWEEN_ATTEMPTS` (env prop)
|
||||
|1000
|
||||
|Number of milliseconds to wait between attempts to push the commits to `origin`
|
||||
|====
|
||||
@@ -1,20 +0,0 @@
|
||||
:numbered!:
|
||||
[appendix]
|
||||
[[common-application-properties]]
|
||||
== Common application properties
|
||||
|
||||
include::_attributes.adoc[]
|
||||
|
||||
Various properties can be specified inside your `application.properties` file, inside your `application.yml` file, or as command line switches.
|
||||
This appendix provides a list of common {project-full-name} properties and references to the underlying classes that consume them.
|
||||
|
||||
NOTE: Property contributions can come from additional jar files on your classpath, so you should not consider this an exhaustive list.
|
||||
Also, you can define your own properties.
|
||||
|
||||
=== Default application properties
|
||||
|
||||
include::_configprops.adoc[]
|
||||
|
||||
=== Additional application properties
|
||||
|
||||
include::_additional-stubrunner-configprops.adoc[]
|
||||
@@ -1,628 +0,0 @@
|
||||
[[docker]]
|
||||
= Docker Project
|
||||
include::_attributes.adoc[]
|
||||
|
||||
In this section, we publish a `springcloud/spring-cloud-contract` Docker image
|
||||
that contains a project that generates tests and runs them in `EXPLICIT` mode
|
||||
against a running application.
|
||||
|
||||
TIP: The `EXPLICIT` mode means that the tests generated from contracts send
|
||||
real requests and not mocked ones.
|
||||
|
||||
We also publish a `spring-cloud/spring-cloud-contract-stub-runner` Docker image
|
||||
that starts the standalone version of Stub Runner.
|
||||
|
||||
[[docker-intro]]
|
||||
== A Short Introduction to Maven, JARs, and Binary Storage
|
||||
|
||||
Since non-JVM projects can use the Docker image, it is good to
|
||||
explain the basic terms behind Spring Cloud Contract packaging defaults.
|
||||
|
||||
Parts of the following definitions were taken from the https://maven.apache.org/glossary.html[Maven Glossary]:
|
||||
|
||||
- `Project`: Maven thinks in terms of projects. Projects
|
||||
are all you build. Those projects follow a well defined
|
||||
"`Project Object Model`". Projects can depend on other projects --
|
||||
in that case, the latter are called "`dependencies`". A project may
|
||||
consistent of several subprojects. However, these subprojects are still
|
||||
treated equally as projects.
|
||||
- `Artifact`: An artifact is something that is either produced or used
|
||||
by a project. Examples of artifacts produced by Maven for a project
|
||||
include JAR files and source and binary distributions. Each artifact
|
||||
is uniquely identified by a group ID and an artifact ID that is
|
||||
unique within a group.
|
||||
- `JAR`: JAR stands for Java ARchive. Its format is based on
|
||||
the ZIP file format. Spring Cloud Contract packages the contracts and generated
|
||||
stubs in a JAR file.
|
||||
- `GroupId`: A group ID is a universally unique identifier for a project.
|
||||
While this is often just the project name (for example, `commons-collections`),
|
||||
it is helpful to use a fully-qualified package name to distinguish it
|
||||
from other projects with a similar name (for example, `org.apache.maven`).
|
||||
Typically, when published to the Artifact Manager, the `GroupId` gets
|
||||
slash separated and forms part of the URL. For example, for a group ID of `com.example`
|
||||
and an artifact ID of `application`, the result would be `/com/example/application/`.
|
||||
- `Classifier`: The Maven dependency notation looks as follows:
|
||||
`groupId:artifactId:version:classifier`. The classifier is an additional suffix
|
||||
passed to the dependency -- for example, `stubs` or `sources`. The same dependency
|
||||
(for example, `com.example:application`) can produce multiple artifacts that
|
||||
differ from each other with the classifier.
|
||||
- `Artifact manager`: When you generate binaries, sources, or packages, you would
|
||||
like them to be available for others to download, reference, or reuse. In the case
|
||||
of the JVM world, those artifacts are generally JARs. For Ruby, those artifacts are gems.
|
||||
For Docker, those artifacts are Docker images. You can store those artifacts
|
||||
in a manager. Examples of such managers include https://jfrog.com/artifactory/[Artifactory]
|
||||
and https://www.sonatype.org/nexus/[Nexus].
|
||||
|
||||
[[docker-how-it-works]]
|
||||
== Generating Tests on the Producer Side
|
||||
|
||||
The image searches for contracts under the `/contracts` folder.
|
||||
The output from running the tests is available in the
|
||||
`/spring-cloud-contract/build` folder (useful for debugging
|
||||
purposes).
|
||||
|
||||
You can mount your contracts and pass the environment variables.
|
||||
The image then:
|
||||
|
||||
- Generates the contract tests
|
||||
- Runs the tests against the provided URL
|
||||
- Generates the https://github.com/tomakehurst/wiremock[WireMock] stubs
|
||||
- Publishes the stubs to a Artifact Manager (optional -- turned on by default)
|
||||
|
||||
[[docker-env-vars]]
|
||||
=== Environment Variables
|
||||
|
||||
The Docker image requires some environment variables to point to
|
||||
your running application, to the Artifact manager instance, and so on.
|
||||
The following list describes the environment variables:
|
||||
|
||||
// TODO: reenable
|
||||
//include::{project-root}/docker/spring-cloud-contract-docker/target/adoc/props.adoc[indent=0]
|
||||
|
||||
The following environment variables are used when tests are run:
|
||||
|
||||
// TODO: reenable
|
||||
//include::{project-root}/docker/spring-cloud-contract-docker/target/adoc/appProps.adoc[indent=0]
|
||||
|
||||
### Customizing the gradle build
|
||||
|
||||
You can provide a customized `gradle.build` to be run in the container by mounting your customized build file as a volume when running the container:
|
||||
|
||||
====
|
||||
[source,bash]
|
||||
----
|
||||
$ docker run -v <absolute-path-of-your-custom-file>:/spring-cloud-contract/build.gradle springcloud/spring-cloud-contract:<version>
|
||||
----
|
||||
====
|
||||
|
||||
[[docker-example-of-usage]]
|
||||
=== Example of Usage via HTTP
|
||||
|
||||
In this section, we explore a simple MVC application. To get started, clone the following
|
||||
git repository and cd to the resulting directory, by running the following commands:
|
||||
|
||||
====
|
||||
[source,bash]
|
||||
----
|
||||
$ git clone https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs
|
||||
$ cd bookstore
|
||||
----
|
||||
====
|
||||
|
||||
The contracts are available in the `/contracts` folder.
|
||||
|
||||
Since we want to run tests, we can run the following command:
|
||||
|
||||
====
|
||||
[source,bash]
|
||||
----
|
||||
$ npm test
|
||||
----
|
||||
====
|
||||
|
||||
However, for learning purposes, we split it into pieces, as follows:
|
||||
|
||||
====
|
||||
[source,bash]
|
||||
----
|
||||
# Stop docker infra (nodejs, artifactory)
|
||||
$ ./stop_infra.sh
|
||||
# Start docker infra (nodejs, artifactory)
|
||||
$ ./setup_infra.sh
|
||||
|
||||
# Kill & Run app
|
||||
$ pkill -f "node app"
|
||||
$ nohup node app &
|
||||
|
||||
# Prepare environment variables
|
||||
$ SC_CONTRACT_DOCKER_VERSION="..."
|
||||
$ APP_IP="192.168.0.100"
|
||||
$ APP_PORT="3000"
|
||||
$ ARTIFACTORY_PORT="8081"
|
||||
$ APPLICATION_BASE_URL="http://${APP_IP}:${APP_PORT}"
|
||||
$ ARTIFACTORY_URL="http://${APP_IP}:${ARTIFACTORY_PORT}/artifactory/libs-release-local"
|
||||
$ CURRENT_DIR="$( pwd )"
|
||||
$ CURRENT_FOLDER_NAME=${PWD##*/}
|
||||
$ PROJECT_VERSION="0.0.1.RELEASE"
|
||||
|
||||
# Run contract tests
|
||||
$ docker run --rm -e "APPLICATION_BASE_URL=${APPLICATION_BASE_URL}" -e "PUBLISH_ARTIFACTS=true" -e "PROJECT_NAME=${CURRENT_FOLDER_NAME}" -e "REPO_WITH_BINARIES_URL=${ARTIFACTORY_URL}" -e "PROJECT_VERSION=${PROJECT_VERSION}" -v "${CURRENT_DIR}/contracts/:/contracts:ro" -v "${CURRENT_DIR}/node_modules/spring-cloud-contract/output:/spring-cloud-contract-output/" springcloud/spring-cloud-contract:"${SC_CONTRACT_DOCKER_VERSION}"
|
||||
|
||||
# Kill app
|
||||
$ pkill -f "node app"
|
||||
----
|
||||
====
|
||||
|
||||
Through bash scripts, the following happens:
|
||||
|
||||
- The infrastructure (MongoDb and Artifactory) is set up.
|
||||
In a real-life scenario, you would run the NodeJS application
|
||||
with a mocked database. In this example, we want to show how we can
|
||||
benefit from Spring Cloud Contract in very little time.
|
||||
- Due to those constraints, the contracts also represent the
|
||||
stateful situation.
|
||||
** The first request is a `POST` that causes data to get inserted into the database.
|
||||
** The second request is a `GET` that returns a list of data with 1 previously inserted element.
|
||||
- The NodeJS application is started (on port `3000`).
|
||||
- The contract tests are generated through Docker, and tests
|
||||
are run against the running application.
|
||||
** The contracts are taken from `/contracts` folder.
|
||||
** The output of the test is available under
|
||||
`node_modules/spring-cloud-contract/output`.
|
||||
- The stubs are uploaded to Artifactory. You can find them in
|
||||
http://localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/.
|
||||
The stubs are at http://localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/bookstore-0.0.1.RELEASE-stubs.jar.
|
||||
|
||||
[[docker-example-of-usage-messaging]]
|
||||
=== Example of Usage via Messaging
|
||||
|
||||
If you want to use Spring Cloud Contract with messaging via the Docker images (e.g.
|
||||
in case of polyglot applications) then you'll have to have the following prerequisites met:
|
||||
|
||||
* Middleware (e.g. RabbitMQ or Kafka) must be running before generating tests
|
||||
* Your contract needs to call a method `triggerMessage(...)` with a `String` parameter that is equal to the contract's `label`.
|
||||
* Your application needs to have a HTTP endpoint via which we can trigger a message
|
||||
** That endpoint should not be available on production (could be enabled via an environment variable)
|
||||
|
||||
[[docker-example-of-usage-messaging-contract]]
|
||||
==== Example of a Messaging Contract
|
||||
|
||||
The contract needs to call a `triggerMessage(...)` method. That method is already provided in the base class for all tests in the docker image and will send out a request to the HTTP endpoint on the producer side. Below you can find examples of such contracts.
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Groovy
|
||||
----
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
|
||||
Contract.make {
|
||||
description 'Send a pong message in response to a ping message'
|
||||
label 'ping_pong'
|
||||
input {
|
||||
// You have to provide the `triggerMessage` method with the `label`
|
||||
// as a String parameter of the method
|
||||
triggeredBy('triggerMessage("ping_pong")')
|
||||
}
|
||||
outputMessage {
|
||||
sentTo('output')
|
||||
body([
|
||||
message: 'pong'
|
||||
])
|
||||
}
|
||||
metadata(
|
||||
[amqp:
|
||||
[
|
||||
outputMessage: [
|
||||
connectToBroker: [
|
||||
declareQueueWithName: "queue"
|
||||
],
|
||||
messageProperties: [
|
||||
receivedRoutingKey: '#'
|
||||
]
|
||||
]
|
||||
]
|
||||
])
|
||||
}
|
||||
----
|
||||
|
||||
[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.YAML
|
||||
----
|
||||
description: 'Send a pong message in response to a ping message'
|
||||
label: 'ping_pong'
|
||||
input:
|
||||
# You have to provide the `triggerMessage` method with the `label`
|
||||
# as a String parameter of the method
|
||||
triggeredBy: 'triggerMessage("ping_pong")'
|
||||
outputMessage:
|
||||
sentTo: 'output'
|
||||
body:
|
||||
message: 'pong'
|
||||
metadata:
|
||||
amqp:
|
||||
outputMessage:
|
||||
connectToBroker:
|
||||
declareQueueWithName: "queue"
|
||||
messageProperties:
|
||||
receivedRoutingKey: '#'
|
||||
----
|
||||
====
|
||||
|
||||
[[docker-example-of-usage-messaging-endpoint]]
|
||||
==== HTTP Endpoint to Trigger a Message
|
||||
|
||||
Why is there need to develop such an endpoint? Spring Cloud Contract
|
||||
would have to generate code in various languages (as it does in Java) to make it possible to trigger production
|
||||
code that sends a message to a broker. If such code is not generated then we need to be able to trigger the message anyways, and the way to do it is to provide an HTTP endpoint that the user will prepare in the language of their choosing.
|
||||
|
||||
The endpoint must have the following configuration:
|
||||
|
||||
- URL: `/springcloudcontract/{label}` where `label` can be any text
|
||||
- Method: `POST`
|
||||
- Basing on the `label` will generate a message that will be sent to a given destination according to the contract definition
|
||||
|
||||
Below you have an example of such an endpoint. If you're interested in
|
||||
providing an example in your language don't hesitate to file an issue in
|
||||
the https://github.com/spring-cloud/spring-cloud-contract/issues/new?assignees=&labels=&template=feature_request.md&title=New+Polyglot+Sample+of+a+HTTP+controller[Spring Cloud Contract repository at Github].
|
||||
|
||||
====
|
||||
[source,python,indent=0,subs="verbatim,attributes"]
|
||||
.Python
|
||||
----
|
||||
#!/usr/bin/env python
|
||||
|
||||
from flask import Flask
|
||||
from flask import jsonify
|
||||
import pika
|
||||
import os
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# Production code that sends a message to RabbitMQ
|
||||
def send_message(cmd):
|
||||
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
|
||||
channel = connection.channel()
|
||||
channel.basic_publish(
|
||||
exchange='output',
|
||||
routing_key='#',
|
||||
body=cmd,
|
||||
properties=pika.BasicProperties(
|
||||
delivery_mode=2, # make message persistent
|
||||
))
|
||||
connection.close()
|
||||
return " [x] Sent via Rabbit: %s" % cmd
|
||||
|
||||
# This should be ran in tests (shouldn't be publicly available)
|
||||
if 'CONTRACT_TEST' in os.environ:
|
||||
@app.route('/springcloudcontract/<label>', methods=['POST'])
|
||||
def springcloudcontract(label):
|
||||
if label == "ping_pong":
|
||||
return send_message('{"message":"pong"}')
|
||||
else:
|
||||
raise ValueError('No such label expected.')
|
||||
----
|
||||
====
|
||||
|
||||
[[docker-example-of-usage-messaging-producer]]
|
||||
==== Running Message Tests on the Producer Side
|
||||
|
||||
Now, let's generate tests from contracts to test the producer side.
|
||||
We will run bash code to start the Docker image
|
||||
with attached contracts, however we will also add variables for the messaging
|
||||
code to work. In this case let's assume that the contracts are being stored in
|
||||
a Git repository.
|
||||
|
||||
====
|
||||
[source,bash]
|
||||
----
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
CURRENT_DIR="$( pwd )"
|
||||
|
||||
export SC_CONTRACT_DOCKER_VERSION="${SC_CONTRACT_DOCKER_VERSION:-4.0.1-SNAPSHOT}"
|
||||
export APP_IP="$( ./whats_my_ip.sh )"
|
||||
export APP_PORT="${APP_PORT:-8000}"
|
||||
export APPLICATION_BASE_URL="http://${APP_IP}:${APP_PORT}"
|
||||
export PROJECT_GROUP="${PROJECT_GROUP:-group}"
|
||||
export PROJECT_NAME="${PROJECT_NAME:-application}"
|
||||
export PROJECT_VERSION="${PROJECT_VERSION:-0.0.1-SNAPSHOT}"
|
||||
export PRODUCER_STUBS_CLASSIFIER="${PRODUCER_STUBS_CLASSIFIER:-stubs}"
|
||||
export FAIL_ON_NO_CONTRACTS="${FAIL_ON_NO_CONTRACTS:-false}"
|
||||
# In our Python app we want to enable the HTTP endpoint
|
||||
export CONTRACT_TEST="true"
|
||||
# In the Verifier docker container we want to add support for RabbitMQ
|
||||
export MESSAGING_TYPE="rabbit"
|
||||
|
||||
# Let's start the infrastructure (e.g. via Docker Compose)
|
||||
yes | docker-compose kill || echo "Nothing running"
|
||||
docker-compose up -d
|
||||
|
||||
echo "SC Contract Version [${SC_CONTRACT_DOCKER_VERSION}]"
|
||||
echo "Application URL [${APPLICATION_BASE_URL}]"
|
||||
echo "Project Version [${PROJECT_VERSION}]"
|
||||
|
||||
# Let's run python app
|
||||
gunicorn -w 4 --bind 0.0.0.0 main:app &
|
||||
APP_PID=$!
|
||||
|
||||
# Generate and run tests
|
||||
docker run --rm \
|
||||
--name verifier \
|
||||
# For the image to find the RabbitMQ running in another container
|
||||
-e "SPRING_RABBITMQ_ADDRESSES=${APP_IP}:5672" \
|
||||
# We need to tell the container what messaging middleware we will use
|
||||
-e "MESSAGING_TYPE=${MESSAGING_TYPE}" \
|
||||
-e "PUBLISH_STUBS_TO_SCM=false" \
|
||||
-e "PUBLISH_ARTIFACTS=false" \
|
||||
-e "APPLICATION_BASE_URL=${APPLICATION_BASE_URL}" \
|
||||
-e "PROJECT_NAME=${PROJECT_NAME}" \
|
||||
-e "PROJECT_GROUP=${PROJECT_GROUP}" \
|
||||
-e "PROJECT_VERSION=${PROJECT_VERSION}" \
|
||||
-e "EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL=git://https://github.com/marcingrzejszczak/cdct_python_contracts.git" \
|
||||
-e "EXTERNAL_CONTRACTS_ARTIFACT_ID=${PROJECT_NAME}" \
|
||||
-e "EXTERNAL_CONTRACTS_GROUP_ID=${PROJECT_GROUP}" \
|
||||
-e "EXTERNAL_CONTRACTS_VERSION=${PROJECT_VERSION}" \
|
||||
-v "${CURRENT_DIR}/build/spring-cloud-contract/output:/spring-cloud-contract-output/" \
|
||||
springcloud/spring-cloud-contract:"${SC_CONTRACT_DOCKER_VERSION}"
|
||||
|
||||
kill $APP_PID
|
||||
|
||||
yes | docker-compose kill
|
||||
----
|
||||
====
|
||||
|
||||
What will happen is:
|
||||
|
||||
- Tests will be generated from contracts taken from Git
|
||||
- In the contract we've provided an entry in metadata called `declareQueueWithName` that will lead to creation of a queue in RabbitMQ with the given name *before* the request to trigger the message is sent
|
||||
- Via the `triggerMessage("ping_pong")` method call a POST request to the Python application to the `/springcloudcontract/ping_pong` endpoint will be made
|
||||
- The Python application will generate and send a `'{"message":"pong"}'` JSON via RabbitMQ to an exchange called `output`
|
||||
- The generated test will poll for a message sent to the `output` exchange
|
||||
- Once the message was received will assert its contents
|
||||
|
||||
After the tests have passed we know that the message was properly sent from the Python app to RabbitMQ.
|
||||
|
||||
[[docker-stubrunner]]
|
||||
== Running Stubs on the Consumer Side
|
||||
|
||||
This section describes how to use Docker on the consumer side to fetch and run stubs.
|
||||
|
||||
We publish a `spring-cloud/spring-cloud-contract-stub-runner` Docker image
|
||||
that starts the standalone version of Stub Runner.
|
||||
|
||||
[[docker-stubrunner-security]]
|
||||
=== Security
|
||||
|
||||
Since the Spring Cloud Contract Stub Runner Docker Image uses the standalone version of Stub Runner the same security considerations need to be taken. You can read more about those link:project-features.html#features-stub-runner-boot-security[in this section of the documentation].
|
||||
|
||||
[[docker-stubrunner-env-vars]]
|
||||
=== Environment Variables
|
||||
|
||||
You can run the docker image and pass any of the <<project-features.adoc#features-stub-runner-common-properties-junit-spring, common properties for JUnit and Spring>>
|
||||
as environment variables. The convention is that all the
|
||||
letters should be upper case.
|
||||
The dot (`.`) should be replaced with underscore (`_`) characters. For example,
|
||||
the `stubrunner.repositoryRoot` property should be represented
|
||||
as a `STUBRUNNER_REPOSITORY_ROOT` environment variable.
|
||||
|
||||
In addition to those variables you can set the following ones:
|
||||
|
||||
- `MESSAGING_TYPE` - what type of messaging system are you using (currently supported are `rabbit`, `kafka`)
|
||||
- `ADDITIONAL_OPTS` - any additional properties that you would like to pass to the application
|
||||
|
||||
[[docker-stubrunner-example]]
|
||||
=== Example of Usage
|
||||
|
||||
We want to use the stubs created in this <<docker-server-side>> step.
|
||||
Assume that we want to run the stubs on port `9876`. You can see the NodeJS code
|
||||
by cloning the repository and changing to the directory indicated in the following commands:
|
||||
|
||||
====
|
||||
[source,bash]
|
||||
----
|
||||
$ git clone https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs
|
||||
$ cd bookstore
|
||||
----
|
||||
====
|
||||
|
||||
Now we can run the Stub Runner Boot application with the stubs, by running the following
|
||||
commands:
|
||||
|
||||
====
|
||||
[source,bash]
|
||||
----
|
||||
# Provide the Spring Cloud Contract Docker version
|
||||
$ SC_CONTRACT_DOCKER_VERSION="..."
|
||||
# The IP at which the app is running and Docker container can reach it
|
||||
$ APP_IP="192.168.0.100"
|
||||
# Spring Cloud Contract Stub Runner properties
|
||||
$ STUBRUNNER_PORT="8083"
|
||||
# Stub coordinates 'groupId:artifactId:version:classifier:port'
|
||||
$ STUBRUNNER_IDS="com.example:bookstore:0.0.1.RELEASE:stubs:9876"
|
||||
$ STUBRUNNER_REPOSITORY_ROOT="http://${APP_IP}:8081/artifactory/libs-release-local"
|
||||
# Run the docker with Stub Runner Boot
|
||||
$ docker run --rm \
|
||||
-e "STUBRUNNER_IDS=${STUBRUNNER_IDS}" \
|
||||
-e "STUBRUNNER_REPOSITORY_ROOT=${STUBRUNNER_REPOSITORY_ROOT}" \
|
||||
-e "STUBRUNNER_STUBS_MODE=REMOTE" \
|
||||
-p "${STUBRUNNER_PORT}:${STUBRUNNER_PORT}" \
|
||||
-p "9876:9876" \
|
||||
springcloud/spring-cloud-contract-stub-runner:"${SC_CONTRACT_DOCKER_VERSION}"
|
||||
----
|
||||
====
|
||||
|
||||
When the preceding commands run,
|
||||
|
||||
- A standalone Stub Runner application gets started.
|
||||
- It downloads the stub with coordinates `com.example:bookstore:0.0.1.RELEASE:stubs` on port `9876`.
|
||||
- It gets downloads from Artifactory running at `http://192.168.0.100:8081/artifactory/libs-release-local`.
|
||||
- After a while, Stub Runner is running on port `8083`.
|
||||
- The stubs are running at port `9876`.
|
||||
|
||||
On the server side, we built a stateful stub. We can use curl to assert
|
||||
that the stubs are setup properly. To do so, run the following commands:
|
||||
|
||||
====
|
||||
[source,bash]
|
||||
----
|
||||
# let's run the first request (no response is returned)
|
||||
$ curl -H "Content-Type:application/json" -X POST --data '{ "title" : "Title", "genre" : "Genre", "description" : "Description", "author" : "Author", "publisher" : "Publisher", "pages" : 100, "image_url" : "https://d213dhlpdb53mu.cloudfront.net/assets/pivotal-square-logo-41418bd391196c3022f3cd9f3959b3f6d7764c47873d858583384e759c7db435.svg", "buy_url" : "https://pivotal.io" }' http://localhost:9876/api/books
|
||||
# Now time for the second request
|
||||
$ curl -X GET http://localhost:9876/api/books
|
||||
# You will receive contents of the JSON
|
||||
----
|
||||
====
|
||||
|
||||
IMPORTANT: If you want use the stubs that you have built locally, on your host,
|
||||
you should set the `-e STUBRUNNER_STUBS_MODE=LOCAL` environment variable and mount
|
||||
the volume of your local m2 (`-v "${HOME}/.m2/:/home/scc/.m2:ro"`).
|
||||
|
||||
[[docker-stubrunner-example-messaging]]
|
||||
=== Example of Usage with Messaging
|
||||
|
||||
In order to make messaging work it's enough to pass the `MESSAGING_TYPE` environment variable with `kafka` or `rabbit` values. This will lead to setting up
|
||||
the Stub Runner Boot Docker image with dependencies required to connect to the broker.
|
||||
|
||||
In order to set the connection properties you can check out Spring Cloud Stream properties page to set proper environment variables.
|
||||
|
||||
// TODO: Change to current or sth
|
||||
* https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#integration-properties[Spring Boot Integration properties]
|
||||
** You can search for `spring.rabbitmq.xxx` or `spring.kafka.xxx` properties
|
||||
* https://docs.spring.io/spring-cloud-stream-binder-rabbit/docs/3.1.0.M1/reference/html/index.html#_configuration_options[Stream specific RabbitMQ properties]
|
||||
* https://docs.spring.io/spring-cloud-stream-binder-kafka/docs/3.1.0.M1/reference/html/index.html#_configuration_options[Stream specific Kafka properties]
|
||||
|
||||
The most common property you would set is the location of the running middlewara.
|
||||
If a property to set it is called `spring.rabbitmq.addresses` or `spring.kafka.bootstrap-servers` then you should name the environment variable `SPRING_RABBITMQ_ADDRESSES` and `SPRING_KAFKA_BOOTSTRAP_SERVERS` respectively.
|
||||
|
||||
[[docker-middleware-standalone]]
|
||||
== Running Contract Tests against Existing Middleware
|
||||
|
||||
There is legitimate reason to run your contract tests against existing middleware. Some
|
||||
testing frameworks might give you false positive results - the test within your build
|
||||
passes whereas on production the communication fails.
|
||||
|
||||
In Spring Cloud Contract docker images we give an option to connect to existing middleware.
|
||||
As presented in previous subsections we do support Kafka and RabbitMQ out of the box. However,
|
||||
via https://camel.apache.org/components/latest/index.html[Apache Camel Components] we can support
|
||||
other middleware too. Let's take a look at the following examples of usage.
|
||||
|
||||
[[docker-verifier-running-middlware]]
|
||||
=== Spring Cloud Contract Docker and running Middleware
|
||||
|
||||
In order to connect to arbitrary middleware, we'll leverage the `standalone` metadata entry
|
||||
in the contract section.
|
||||
|
||||
[source,yaml,indent=0]
|
||||
----
|
||||
description: 'Send a pong message in response to a ping message'
|
||||
label: 'standalone_ping_pong' <1>
|
||||
input:
|
||||
triggeredBy: 'triggerMessage("ping_pong")' <2>
|
||||
outputMessage:
|
||||
sentTo: 'rabbitmq:output' <3>
|
||||
body: <4>
|
||||
message: 'pong'
|
||||
metadata:
|
||||
standalone: <5>
|
||||
setup: <6>
|
||||
options: rabbitmq:output?queue=output&routingKey=# <7>
|
||||
outputMessage: <8>
|
||||
additionalOptions: routingKey=#&queue=output <9>
|
||||
----
|
||||
<1> Label by which we'll be able to trigger the message via Stub Runner
|
||||
<2> As in the previous messaging examples we'll need to trigger the HTTP endpoint in the running application to make it send a message according to the provided protocol
|
||||
<3> `protocol:destination` as requested by Apache Camel
|
||||
<4> Output message body
|
||||
<5> Standalone metadata entry
|
||||
<6> Setup part will contain information about how to prepare for running contract tests before the actual call to HTTP endpoint of the running application is made
|
||||
<7> Apache Camel URI to be called in the setup phase. In this case we will try to poll for a message at the `output` exchange and due to to having the `queue=output` and `routingKey=#` a queue with name `output` will be set and bound to the `output` exchange with routing key `#`
|
||||
<8> Additional options (more technical ones) to be appended to the `protocol:destination` from point (3) - together will be combined in the following format `rabbitmq:output?routingKey=#&queue=output`.
|
||||
|
||||
For the contract tests to pass we will need as usual in case of messaging in polyglot environment
|
||||
a running application and running middleware. This time we will have different environment variables set for the Spring Cloud Contract Docker image.
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
# Setup
|
||||
# Run the middleware
|
||||
docker-compose up -d rabbitmq <1>
|
||||
|
||||
# Run the python application
|
||||
gunicorn -w 4 --bind 0.0.0.0 main:app & <2>
|
||||
APP_PID=$!
|
||||
|
||||
docker run --rm \
|
||||
--name verifier \
|
||||
-e "STANDALONE_PROTOCOL=rabbitmq" \ <3>
|
||||
-e "CAMEL_COMPONENT_RABBITMQ_ADDRESSES=172.18.0.1:5672" \ <4>
|
||||
-e "PUBLISH_STUBS_TO_SCM=false" \
|
||||
-e "PUBLISH_ARTIFACTS=false" \
|
||||
-e "APPLICATION_BASE_URL=172.18.0.1" \
|
||||
-e "PROJECT_NAME=application" \
|
||||
-e "PROJECT_GROUP=group" \
|
||||
-e "EXTERNAL_CONTRACTS_ARTIFACT_ID=application" \
|
||||
-e "EXTERNAL_CONTRACTS_GROUP_ID=group" \
|
||||
-e "EXTERNAL_CONTRACTS_VERSION=0.0.1-SNAPSHOT" \
|
||||
-v "${CURRENT_DIR}/build/spring-cloud-contract/output:/spring-cloud-contract-output/" \
|
||||
springcloud/spring-cloud-contract:"${SC_CONTRACT_DOCKER_VERSION}"
|
||||
|
||||
|
||||
# Teardown
|
||||
kill $APP_PID
|
||||
yes | docker-compose kill
|
||||
----
|
||||
<1> We need to have the middleware running first
|
||||
<2> The application needs to be up and running
|
||||
<3> Via the `STANDALONE_PROTOCOL` environment variable we will fetch a https://camel.apache.org/components/latest/index.html[Apache Camel Component]. The artifact that we will fetch is `org.apache.camel.springboot:camel-${STANDALONE_PROTOCOL}-starter`. In other words `STANDALONE_PROTOCOL` is matching Camel's component.
|
||||
<4> We're setting addresses (we could be setting credentials) via Camel's Spring Boot Starter mechanisms. Example for https://camel.apache.org/components/latest/rabbitmq-component.html#_spring_boot_auto_configuration[Apache Camel's RabbitMQ Spring Boot Auto-Configuration]
|
||||
|
||||
[[docker-stubrunner-running-middlware]]
|
||||
=== Stub Runner Docker and running Middleware
|
||||
|
||||
In order to trigger a stub message against running middleware, we can run Stub Runner Docker image in the following manner.
|
||||
|
||||
Example of usage
|
||||
|
||||
```bash
|
||||
$ docker run \
|
||||
-e "CAMEL_COMPONENT_RABBITMQ_ADDRESSES=172.18.0.1:5672" \ <1>
|
||||
-e "STUBRUNNER_IDS=group:application:0.0.1-SNAPSHOT" \ <2>
|
||||
-e "STUBRUNNER_REPOSITORY_ROOT=git://https://github.com/marcingrzejszczak/cdct_python_contracts.git" \ <3>
|
||||
-e ADDITIONAL_OPTS="--thin.properties.dependencies.rabbitmq=org.apache.camel.springboot:camel-rabbitmq-starter:3.4.0" \ <4>
|
||||
-e "STUBRUNNER_STUBS_MODE=REMOTE" \ <5>
|
||||
-v "${HOME}/.m2/:/home/scc/.m2:ro" \ <6>
|
||||
-p 8750:8750 \ <7>
|
||||
springcloud/spring-cloud-contract-stub-runner:3.0.4-SNAPSHOT <8>
|
||||
```
|
||||
<1> We're injecting the address of RabbitMQ via https://camel.apache.org/components/latest/rabbitmq-component.html#_spring_boot_auto_configuration[Apache Camel's Spring Boot Auto-Configuration]
|
||||
<2> We're telling Stub Runner which stubs to download
|
||||
<3> We're providing an external location for our stubs (Git repository)
|
||||
<4> Via the `ADDITIONAL_OPTS=--thin.properties.dependencies.XXX=GROUP:ARTIFACT:VERSION` property we're telling Stub Runner which additional dependency to fetch at runtime. In this case we want to fetch `camel-rabbitmq-starter` so `XXX` is a random string and we want to fetch `org.apache.camel.springboot:camel-rabbitmq-starter` artifact in version `3.4.0`.
|
||||
<5> Since we're using Git, the remote option of fetching stubs needs to be set
|
||||
<6> So that we speed up launching of Stub Runner, we're attaching our local Maven repository `.m2` as a volume. If you don't have it populated you can consider setting the write permissions via `:rw` instead read only `:ro`.
|
||||
<7> We expose the port `8750` at which Stub Runner is running.
|
||||
<8> Coordinates of the Stub Runner Docker image.
|
||||
|
||||
After a while you'll notice the following text in your console, which means that Stub Runner is ready to accept requests.
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
o.a.c.impl.engine.AbstractCamelContext : Apache Camel 3.4.3 (camel-1) started in 0.007 seconds
|
||||
o.s.c.c.s.server.StubRunnerBoot : Started StubRunnerBoot in 14.483 seconds (JVM running for 18.666)
|
||||
o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
|
||||
o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
|
||||
o.s.web.servlet.DispatcherServlet : Completed initialization in 2 ms
|
||||
----
|
||||
|
||||
To get the list of triggers you can send an HTTP GET request to `localhost:8750/triggers` endpoint. To trigger a stub message, you can send a HTTP POST request to `localhost:8750/triggers/standalone_ping_pong`. In the console you'll see:
|
||||
|
||||
[source,bash.indent=0]
|
||||
----
|
||||
o.s.c.c.v.m.camel.CamelStubMessages : Will send a message to URI [rabbitmq:output?routingKey=#&queue=output]
|
||||
----
|
||||
|
||||
If you check the RabbitMQ management console, you'll see that there's 1 message available in the `output` queue.
|
||||
@@ -1,127 +0,0 @@
|
||||
[[documentation]]
|
||||
= Spring Cloud Contract Documentation
|
||||
include::_attributes.adoc[]
|
||||
|
||||
This section provides a brief overview of {project-full-name} reference documentation. It serves
|
||||
as a map for the rest of the document.
|
||||
|
||||
|
||||
|
||||
[[contract-documentation-about]]
|
||||
== About the Documentation
|
||||
|
||||
The {project-full-name} reference guide is available as
|
||||
|
||||
* {docs-url}/reference/html[Multi-page HTML]
|
||||
* {docs-url}/reference/htmlsingle[Single-page HTML]
|
||||
* {docs-url}/reference/pdf/{project-name}.pdf[PDF]
|
||||
|
||||
Copies of this document may be made for your own use and for distribution to others,
|
||||
provided that you do not charge any fee for such copies and further provided that each
|
||||
copy contains this Copyright Notice, whether distributed in print or electronically.
|
||||
|
||||
|
||||
|
||||
[[documentation-getting-help]]
|
||||
== Getting Help
|
||||
If you have trouble with {project-full-name}, we would like to help.
|
||||
|
||||
* Try the <<howto.adoc#howto, How-to documents>>. They provide solutions to the most
|
||||
common questions.
|
||||
* Learn the {project-full-name} basics. If you are
|
||||
starting out with {project-full-name}, try one of the https://spring.io/guides[guides].
|
||||
* Ask a question. We monitor https://stackoverflow.com[stackoverflow.com] for questions
|
||||
tagged with https://stackoverflow.com/tags/{project-name}[`{project-name}`].
|
||||
* Report bugs with {project-full-name} at https://github.com/spring-cloud/{project-name}/issues.
|
||||
* Chat with us at http://https://gitter.im/spring-cloud/{project-name}[{project-full-name} Gitter]
|
||||
|
||||
NOTE: All of {project-full-name} is open source, including the documentation. If you find
|
||||
problems with the docs or if you want to improve them, please {github-code}[get
|
||||
involved].
|
||||
|
||||
|
||||
[[contract-documentation-first-steps]]
|
||||
== First Steps
|
||||
If you are getting started with {project-full-name} or 'Spring' in general, start with
|
||||
<<getting-started.adoc#getting-started, the following topics>>:
|
||||
|
||||
* *From scratch:*
|
||||
<<getting-started.adoc#getting-started-introducing-{project-name}, Overview>> |
|
||||
<<getting-started.adoc#getting-started-three-second-tour, Three-second Tour>> |
|
||||
<<getting-started.adoc#getting-started-first-application, First application>>
|
||||
* *Tutorial:*
|
||||
<<getting-started.adoc#getting-started-cdc, Introduction>> |
|
||||
<<getting-started.adoc#consumer-side-loan-issuance, Consumer, Part 1>> |
|
||||
<<getting-started.adoc#producer-side-fraud-detection-server, Producer>> |
|
||||
<<getting-started.adoc#consumer-side-loan-issuance-final-step, Consumer, Part 2>>
|
||||
|
||||
|
||||
|
||||
== Working with {project-full-name}
|
||||
Ready to actually start using {project-full-name}? <<using.adoc#using, We have
|
||||
you covered>>:
|
||||
|
||||
* *Provider contract testing:*
|
||||
|
||||
** <<using.adoc#flows-provider-nexus,Provider contract testing with stubs in Nexus or Artifactory>>
|
||||
** <<using.adoc#flows-provider-git,Provider contract testing with stubs in Git>>
|
||||
** <<using.adoc#flows-provider-non-spring,Provider contract testing with stubs in Artifactory for a non-Spring application>>
|
||||
** <<using.adoc#flows-provider-non-jvm,Provider contract testing with stubs in Artifactory in non JVM world>>
|
||||
** <<using.adoc#flows-provider-rest-docs,Provider contract testing with REST Docs and stubs in Nexus / Artifactory>>
|
||||
|
||||
* *Consumer-Driven contract testing:*
|
||||
** <<using.adoc#flows-cdc-contracts-producer,Consumer Driven Contracts with contracts on the producer side>>
|
||||
** <<using.adoc#flows-cdc-contracts-external,Consumer Driven Contracts with contracts in external repo>>
|
||||
** <<using.adoc#flows-cdc-contracts-stubs-git,Consumer Driven Contracts with contracts on the producer side, pushed to git>>
|
||||
|
||||
TIP: We talk about *Provider Contracts* when it is the producer of the API that defines the contracts and
|
||||
publishes it for all its consumers to use. This approach is useful for producers that cannot
|
||||
directly collaborate with their consumers -- for example, when there are too many consumers or
|
||||
the consumers are external (do not work within the same company).
|
||||
|
||||
TIP: We use the term, *Consumer-Driven Contracts*, to refer to workflows where the consumers of an API
|
||||
play a vital role in the process of creating the contracts. We recommended this approach, because it is easy
|
||||
to implement when both producer and consumer teams work for the same organizations and the number
|
||||
of consumers is not extremely large.
|
||||
|
||||
== Learning about {project-full-name} Features
|
||||
Need more details about {project-full-name}'s core features?
|
||||
<<project-features.adoc#features, The following content is for you>>:
|
||||
|
||||
* *Core Features:*
|
||||
<<project-features.adoc#contract-dsl, Contract DSL>> |
|
||||
<<project-features.adoc#features-http, Contracts for HTTP>> |
|
||||
<<project-features.adoc#features-messaging, Contracts for Messaging>>
|
||||
* *Integrations:*
|
||||
<<project-features.adoc#features-jax-rs, JAX-RS>> |
|
||||
<<project-features.adoc#features-context-paths, Context Paths>> |
|
||||
<<project-features.adoc#features-rest-docs, RESTDocs>>
|
||||
* *Modules:*
|
||||
<<project-features.adoc#features-stub-runner, Stub Runner>> |
|
||||
<<project-features.adoc#features-wiremock, WireMock>>
|
||||
// TODO: links don't work in "build Tools" section
|
||||
* *Build Tools:*
|
||||
link:maven-project.html[Contract Verifier - Maven] |
|
||||
link:gradle-project.html[Contract Verifier - Gradle] |
|
||||
link:docker-project.html[Docker]
|
||||
|
||||
|
||||
== Advanced Topics
|
||||
Finally, we have a few topics for more advanced users:
|
||||
|
||||
* *Customizing the DSL:*
|
||||
<<advanced.adoc#contract-dsl-customization, DSL Customization>> |
|
||||
<<advanced.adoc#contract-dsl-extending-common-jar, Common JAR>> |
|
||||
<<advanced.adoc#contract-dsl-test-dep, Test Dependency>> |
|
||||
<<advanced.adoc#contract-dsl-plugin-dep, Plugin Dependency>> |
|
||||
<<advanced.adoc#contract-dsl-referencing, Referencing the DSL>>
|
||||
* *Customizing WireMock:*
|
||||
<<advanced.adoc#customization-wiremock-extension, Extensions>> |
|
||||
<<advanced.adoc#customization-wiremock-configuration, Configuration>>
|
||||
* *Customizing {project-full-name}:*
|
||||
<<advanced.adoc#contract-dsl-pluggable-architecture, Pluggable Architecture>> |
|
||||
<<advanced.adoc#contract-dsl-custom-contract-converter, Contract Converter>> |
|
||||
<<advanced.adoc#contract-dsl-custom-test-generator, Test Generator>> |
|
||||
<<advanced.adoc#contract-dsl-custom-stub-generator, Stub Generator>> |
|
||||
<<advanced.adoc#contract-dsl-custom-stub-runner, Stub Runner>> |
|
||||
<<advanced.adoc#contract-dsl-custom-stub-downloader, Stub Downloader>>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,561 +0,0 @@
|
||||
= Gradle Project
|
||||
include::_attributes.adoc[]
|
||||
|
||||
To learn how to set up the Gradle project for Spring Cloud Contract Verifier, read the
|
||||
following sections:
|
||||
|
||||
* <<gradle-prerequisites>>
|
||||
* <<gradle-add-gradle-plugin>>
|
||||
* <<gradle-and-rest-assured>>
|
||||
* <<gradle-snapshot-versions>>
|
||||
* <<gradle-add-stubs>>
|
||||
* <<gradle-default-setup>>
|
||||
* <<gradle-configure-plugin>>
|
||||
* <<gradle-configuration-options>>
|
||||
* <<gradle-single-base-class>>
|
||||
* <<gradle-different-base-classes>>
|
||||
* <<gradle-invoking-generated-tests>>
|
||||
* <<gradle-publishing-stubs-to-artifact-repo>>
|
||||
* <<gradle-pushing-stubs-to-scm>>
|
||||
* <<gradle-consumer>>
|
||||
|
||||
[[gradle-prerequisites]]
|
||||
== Prerequisites
|
||||
|
||||
To use Spring Cloud Contract Verifier with WireMock, you must use either a
|
||||
Gradle or a Maven plugin.
|
||||
|
||||
WARNING: If you want to use Spock in your projects, you must separately add the
|
||||
`spock-core` and `spock-spring` modules. See https://spockframework.github.io/[Spock's
|
||||
documentation] for more information.
|
||||
|
||||
[[gradle-add-gradle-plugin]]
|
||||
== Add Gradle Plugin with Dependencies
|
||||
|
||||
To add a Gradle plugin with dependencies, you can use code similar to the following:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Plugin DSL GA versions
|
||||
----
|
||||
// build.gradle
|
||||
plugins {
|
||||
id "groovy"
|
||||
// this will work only for GA versions of Spring Cloud Contract
|
||||
id "org.springframework.cloud.contract" version "${GAVerifierVersion}"
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${GAVerifierVersion}"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation "org.apache.groovy:groovy-all:${groovyVersion}"
|
||||
// example with adding Spock core and Spock Spring
|
||||
testImplementation "org.spockframework:spock-core:${spockVersion}"
|
||||
testImplementation "org.spockframework:spock-spring:${spockVersion}"
|
||||
testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-verifier'
|
||||
}
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Plugin DSL non GA versions
|
||||
----
|
||||
// settings.gradle
|
||||
pluginManagement {
|
||||
plugins {
|
||||
id "org.springframework.cloud.contract" version "${verifierVersion}"
|
||||
}
|
||||
repositories {
|
||||
// to pick from local .m2
|
||||
mavenLocal()
|
||||
// for snapshots
|
||||
maven { url "https://repo.spring.io/snapshot" }
|
||||
// for milestones
|
||||
maven { url "https://repo.spring.io/milestone" }
|
||||
// for GA versions
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
// build.gradle
|
||||
plugins {
|
||||
id "groovy"
|
||||
id "org.springframework.cloud.contract"
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${verifierVersion}"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation "org.apache.groovy:groovy-all:${groovyVersion}"
|
||||
// example with adding Spock core and Spock Spring
|
||||
testImplementation "org.spockframework:spock-core:${spockVersion}"
|
||||
testImplementation "org.spockframework:spock-spring:${spockVersion}"
|
||||
testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-verifier'
|
||||
}
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Legacy Plugin Application
|
||||
----
|
||||
// build.gradle
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springboot_version}"
|
||||
classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifier_version}"
|
||||
// here you can also pass additional dependencies such as Kotlin spec e.g.:
|
||||
// classpath "org.springframework.cloud:spring-cloud-contract-spec-kotlin:${verifier_version}"
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'groovy'
|
||||
apply plugin: 'org.springframework.cloud.contract'
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${verifier_version}"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation "org.apache.groovy:groovy-all:${groovyVersion}"
|
||||
// example with adding Spock core and Spock Spring
|
||||
testImplementation "org.spockframework:spock-core:${spockVersion}"
|
||||
testImplementation "org.spockframework:spock-spring:${spockVersion}"
|
||||
testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-verifier'
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
[[gradle-and-rest-assured]]
|
||||
== Gradle and Rest Assured 2.0
|
||||
|
||||
By default, Rest Assured 3.x is added to the classpath. However, to use Rest Assured 2.x,
|
||||
you can add it instead, as the following listing shows:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springboot_version}"
|
||||
classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifier_version}"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// all dependencies
|
||||
// you can exclude rest-assured from spring-cloud-contract-verifier
|
||||
testCompile "com.jayway.restassured:rest-assured:2.5.0"
|
||||
testCompile "com.jayway.restassured:spring-mock-mvc:2.5.0"
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
That way, the plugin automatically sees that Rest Assured 2.x is present on the classpath
|
||||
and modifies the imports accordingly.
|
||||
|
||||
[[gradle-snapshot-versions]]
|
||||
== Snapshot Versions for Gradle
|
||||
|
||||
You can add the additional snapshot repository to your `settings.gradle` to use snapshot versions,
|
||||
which are automatically uploaded after every successful build, as the following listing shows:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{standalone_samples_path}/http-server/settings.gradle[tags=repos,indent=0]
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
[[gradle-add-stubs]]
|
||||
== Add stubs
|
||||
|
||||
By default, Spring Cloud Contract Verifier looks for stubs in the
|
||||
`src/contractTest/resources/contracts` directory. For transitional purposes the plugin
|
||||
will also look for contracts in `src/test/resources/contracts`, however, this directory
|
||||
is deprecated as of Spring Cloud Contract 3.0.0.
|
||||
|
||||
It should also be noted, that with this new Gradle source set, you should also migrate
|
||||
any base classes used within your contract tests to `src/contractTest/{language}` where
|
||||
`{language}` should be replaced with Java or Groovy as needed for your purposes.
|
||||
|
||||
The directory that contains stub definitions is treated as a class name, and each stub
|
||||
definition is treated as a single test. Spring Cloud Contract Verifier assumes that it
|
||||
contains at least one level of directories that are to be used as the test class name.
|
||||
If more than one level of nested directories is present, all except the last one is used
|
||||
as the package name. Consider the following structure:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
src/contractTest/resources/contracts/myservice/shouldCreateUser.groovy
|
||||
src/contractTest/resources/contracts/myservice/shouldReturnUser.groovy
|
||||
----
|
||||
====
|
||||
|
||||
Given the preceding structure, Spring Cloud Contract Verifier creates a test class named
|
||||
`defaultBasePackage.MyService` with two methods:
|
||||
|
||||
- `shouldCreateUser()`
|
||||
- `shouldReturnUser()`
|
||||
|
||||
[[gradle-run-plugin]]
|
||||
== Running the Plugin
|
||||
|
||||
The plugin registers itself to be invoked before a `check` task. If you want it to be
|
||||
part of your build process, you need do nothing more. If you want only to generate
|
||||
tests, invoke the `generateContractTests` task.
|
||||
|
||||
[[gradle-default-setup]]
|
||||
== Default Setup
|
||||
|
||||
The default Gradle Plugin setup creates the following Gradle part of the build (in
|
||||
pseudocode):
|
||||
|
||||
====
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
contracts {
|
||||
testFramework ='JUNIT'
|
||||
testMode = 'MockMvc'
|
||||
generatedTestJavaSourcesDir = project.file("${project.buildDir}/generated-test-sources/contractTest/java")
|
||||
generatedTestGroovySourcesDir = project.file("${project.buildDir}/generated-test-sources/contractTest/groovy")
|
||||
generatedTestResourcesDir = project.file("${project.buildDir}/generated-test-resources/contracts")
|
||||
contractsDslDir = project.file("${project.projectDir}/src/contractTest/resources/contracts")
|
||||
basePackageForTests = 'org.springframework.cloud.verifier.tests'
|
||||
stubsOutputDir = project.file("${project.buildDir}/stubs")
|
||||
sourceSet = null
|
||||
}
|
||||
|
||||
def verifierStubsJar = tasks.register(type: Jar, name: 'verifierStubsJar', dependsOn: 'generateClientStubs') {
|
||||
baseName = project.name
|
||||
classifier = contracts.stubsSuffix
|
||||
from contractVerifier.stubsOutputDir
|
||||
}
|
||||
|
||||
def copyContracts = tasks.register(type: Copy, name: 'copyContracts') {
|
||||
from contracts.contractsDslDir
|
||||
into contracts.stubsOutputDir
|
||||
}
|
||||
|
||||
verifierStubsJar.dependsOn copyContracts
|
||||
----
|
||||
====
|
||||
|
||||
[[gradle-configure-plugin]]
|
||||
== Configuring the Plugin
|
||||
|
||||
To change the default configuration, you can add a `contracts` snippet to your Gradle
|
||||
configuration, as the following listing shows:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
contracts {
|
||||
testMode = 'MockMvc'
|
||||
baseClassForTests = 'org.mycompany.tests'
|
||||
generatedTestJavaSourcesDir = project.file('src/generatedContract')
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
To download contracts from a remote source, you can use the following snippets as needed:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
contracts {
|
||||
// If your contracts exist in a JAR archive published to a Maven repository
|
||||
contractDependency {
|
||||
stringNotation = ''
|
||||
// OR
|
||||
groupId = ''
|
||||
artifactId = ''
|
||||
version = ''
|
||||
classifier = ''
|
||||
}
|
||||
|
||||
// If your contracts exist in a Git SCM repository
|
||||
contractRepository {
|
||||
repositoryUrl = ''
|
||||
// username = ''
|
||||
// password = ''
|
||||
}
|
||||
|
||||
// controls the nested location to find the contracts in either the JAR or Git SCM source
|
||||
contractsPath = ''
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Since we are using Gradle's Jar packaging task, there are several options and capabilities that you may wish to utilize to further extend what is created by the `verifierStubsJar`. In order to do this, you would use the native mechanisms provided directly by Gradle for customizing an existing task like so:
|
||||
|
||||
NOTE: for the sake of the example, we desire to add a `git.properties` file to the `verifierStubsJar`.
|
||||
|
||||
====
|
||||
[source,groovy,inden=0]
|
||||
----
|
||||
verifierStubsJar {
|
||||
from("${buildDir}/resources/main/") {
|
||||
include("git.properties")
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
It should also be noted that as of 3.0.0, the default publication has been disabled. As a result this means, that you are able to create any named jar and publish it as you would normally have done via Gradle configuration options. This means that you can build a jar file customized just the way you would like and publish that for absolute full control over the jar's layout and contents.
|
||||
|
||||
[[gradle-configuration-options]]
|
||||
== Configuration Options
|
||||
|
||||
* `testMode`: Defines the mode for acceptance tests. By default, the mode is MockMvc,
|
||||
which is based on Spring's MockMvc. It can also be changed to WebTestClient, JaxRsClient, or
|
||||
Explicit (for real HTTP calls).
|
||||
* `imports`: Creates an array with imports that should be included in the generated tests
|
||||
(for example, `['org.myorg.Matchers']`). By default, it creates an empty array.
|
||||
* `staticImports`: Creates an array with static imports that should be included in
|
||||
generated tests(for example, `['org.myorg.Matchers.*']`). By default, it creates an empty
|
||||
array.
|
||||
* `basePackageForTests`: Specifies the base package for all generated tests. If not set,
|
||||
the value is picked from the package of `baseClassForTests` and from `packageWithBaseClasses`.
|
||||
If neither of these values are set, the value is set to
|
||||
`org.springframework.cloud.contract.verifier.tests`.
|
||||
* `baseClassForTests`: Creates a base class for all generated tests. By default, if you
|
||||
use Spock classes, the class is `spock.lang.Specification`.
|
||||
* `packageWithBaseClasses`: Defines a package where all the base classes reside. This
|
||||
setting takes precedence over `baseClassForTests`.
|
||||
* `baseClassMappings`: Explicitly maps a contract package to a FQN of a base class. This
|
||||
setting takes precedence over `packageWithBaseClasses` and `baseClassForTests`.
|
||||
* `ignoredFiles`: Uses an `Antmatcher` to allow defining stub files for which processing
|
||||
should be skipped. By default, it is an empty array.
|
||||
* `contractsDslDir`: Specifies the directory that contains contracts written by using the
|
||||
GroovyDSL. By default, its value is `$projectDir/src/contractTest/resources/contracts`.
|
||||
* `generatedTestSourcesDir`: Specifies the test source directory where tests generated
|
||||
from the Groovy DSL should be placed. (Deprecrated)
|
||||
* `generatedTestJavaSourcesDir`: Specifies the test source directory where Java/JUnit tests generated from the Groovy DSL should be placed. By default, it's value is `$buildDir/generated-tes-sources/contractTest/java`.
|
||||
* `generatedTestGroovySourcesDir`: Specifies the test source directory where Groovy/Spock tests generated from the Groovy DSL should be placed. By default, it's value is `$buildDir/generated-test-sources/contractTest/groovy`.
|
||||
* `generatedTestResourcesDir`: Specifies the test resource directory where resources used by the tests generated
|
||||
from the Groovy DSL should be placed. By default, its value is
|
||||
`$buildDir/generated-test-resources/contractTest`.
|
||||
* `stubsOutputDir`: Specifies the directory where the generated WireMock stubs from
|
||||
the Groovy DSL should be placed.
|
||||
* `testFramework`: Specifies the target test framework to be used. Currently, Spock, JUnit 4 (`TestFramework.JUNIT`) and
|
||||
JUnit 5 are supported, with JUnit 4 being the default framework.
|
||||
* `contractsProperties`: A map that contains properties to be passed to Spring Cloud Contract
|
||||
components. Those properties might be used by (for example) built-in or custom Stub Downloaders.
|
||||
* `sourceSet`: Source set where the contracts are stored. If not provided will assume `contractTest` (for example, `project.sourceSets.contractTest.java` for JUnit or `project.sourceSets.contractTest.groovy` for Spock).
|
||||
|
||||
You can use the following properties when you want to specify the location of the JAR
|
||||
that contains the contracts:
|
||||
|
||||
* `contractDependency`: Specifies the Dependency that provides
|
||||
`groupid:artifactid:version:classifier` coordinates. You can use the `contractDependency`
|
||||
closure to set it up.
|
||||
* `contractsPath`: Specifies the path to the jar. If contract dependencies are
|
||||
downloaded, the path defaults to `groupid/artifactid`, where `groupid` is slash
|
||||
separated. Otherwise, it scans contracts under the provided directory.
|
||||
* `contractsMode`: Specifies the mode for downloading contracts (whether the
|
||||
JAR is available offline, remotely, and so on).
|
||||
* `deleteStubsAfterTest`: If set to `false`, does not remove any downloaded
|
||||
contracts from temporary directories.
|
||||
* `failOnNoContracts`: When enabled, will throw an exception when no contracts were found. Defaults to `true`.
|
||||
* `failOnInProgress`: If set to `true`, then, if any contracts that are in progress are found, they break the build. On the producer side, you need to be explicit about the fact that you have contracts in progress and take into consideration that you might be causing false positive test results on the consumer side. Defaults to `true`.
|
||||
|
||||
There is also the `contractRepository { ... }` closure that contains the following properties
|
||||
|
||||
* `repositoryUrl`: The URL to the repository with contract definitions
|
||||
* `username` : The repository username
|
||||
* `password` : The repository password
|
||||
* `proxyPort` : The port of the proxy
|
||||
* `proxyHost` : The host of the proxy
|
||||
* `cacheDownloadedContracts` : If set to `true`, caches the folder where non-snapshot contract artifacts got downloaded. Defaults to `true`.
|
||||
|
||||
You can also turn on the following experimental features in the plugin:
|
||||
|
||||
* `convertToYaml`: Converts all DSLs to the declarative YAML format. This can be extremely
|
||||
useful when you use external libraries in your Groovy DSLs. By turning this feature on
|
||||
(by setting it to `true`), you need not add the library dependency on the consumer side.
|
||||
* `assertJsonSize`: You can check the size of JSON arrays in the generated tests. This
|
||||
feature is disabled by default.
|
||||
|
||||
[[gradle-single-base-class]]
|
||||
== Single Base Class for All Tests
|
||||
|
||||
When using Spring Cloud Contract Verifier in MockMvc (the default), you need to create a base
|
||||
specification for all generated acceptance tests. In this class, you need to point to an
|
||||
endpoint, which should be verified. The following example shows how to do so:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{plugins_path}/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/test/groovy/org/springframework/cloud/contract/verifier/twitter/places/BaseMockMvcSpec.groovy[tags=base_class,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
If you use `Explicit` mode, you can use a base class to initialize the whole tested application,
|
||||
as you might see in regular integration tests. If you use the `JAXRSCLIENT` mode, this
|
||||
base class should also contain a `protected WebTarget webTarget` field. Right now, the
|
||||
only option to test the JAX-RS API is to start a web server.
|
||||
|
||||
[[gradle-different-base-classes]]
|
||||
== 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:
|
||||
|
||||
* Follow a convention by providing the `packageWithBaseClasses`
|
||||
* Provide explicit mapping by using `baseClassMappings`
|
||||
|
||||
=== By Convention
|
||||
|
||||
The convention is such that, if you have a contract in (for example)
|
||||
`src/contractTest/resources/contract/foo/bar/baz/` and set the value of the
|
||||
`packageWithBaseClasses` property to `com.example.base`, then Spring Cloud Contract
|
||||
Verifier assumes that there is a `BarBazBase` class under the `com.example.base` package.
|
||||
In other words, the system takes the last two parts of the package, if they exist, and
|
||||
forms a class with a `Base` suffix. This rule takes precedence over `baseClassForTests`.
|
||||
|
||||
=== By Mapping
|
||||
|
||||
You can manually map a regular expression of the contract's package to the fully qualified
|
||||
name of the base class for the matched contract. You have to provide a list called
|
||||
`baseClassMappings` that consists of `baseClassMapping` objects that take a
|
||||
`contractPackageRegex` to `baseClassFQN` mapping.
|
||||
|
||||
Assume that you have contracts in the following directories:
|
||||
|
||||
- `src/contractTest/resources/contract/com/`
|
||||
- `src/contractTest/resources/contract/foo/`
|
||||
|
||||
By providing `baseClassForTests`, we have a fallback in case mapping did not succeed.
|
||||
(You could also provide the `packageWithBaseClasses` as a fallback.) That way, the tests
|
||||
generated from `src/contractTest/resources/contract/com/` contracts extend the
|
||||
`com.example.ComBase`, whereas the rest of the tests extend `com.example.FooBase`.
|
||||
|
||||
[[gradle-invoking-generated-tests]]
|
||||
== Invoking Generated Tests
|
||||
|
||||
To ensure that the provider side is compliant with your defined contracts, you need to run
|
||||
the following command:
|
||||
|
||||
====
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
./gradlew contractTest
|
||||
----
|
||||
====
|
||||
|
||||
[[gradle-publishing-stubs-to-artifact-repo]]
|
||||
== Publishing Stubs to Artifact Repository
|
||||
|
||||
If you use an binary artifact repository to keep the stubs,
|
||||
you will need to configure the publishing section for Gradle to
|
||||
include the `verifierStubsJar`. To do that, you can use the
|
||||
example configuration below:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
maven(MavenPublication) {
|
||||
// other configuration
|
||||
|
||||
artifact verifierStubsJar
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Since 3.0.0, the internal stubs publication has been deprecated
|
||||
and disabled by default. It is recommended to include the
|
||||
`verifierStubsJar` with one of your own publications.
|
||||
|
||||
[[gradle-pushing-stubs-to-scm]]
|
||||
== Pushing Stubs to SCM
|
||||
|
||||
If you use the SCM repository to keep the contracts and
|
||||
stubs, you might want to automate the step of pushing stubs to
|
||||
the repository. To do that, you can call the `pushStubsToScm`
|
||||
task by running the following command:
|
||||
|
||||
====
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
$ ./gradlew pushStubsToScm
|
||||
----
|
||||
====
|
||||
|
||||
Under <<scm-stub-downloader>>, you can find all possible
|
||||
configuration options that you can pass either through
|
||||
the `contractsProperties` field (for example, `contracts { contractsProperties = [foo:"bar"] }`),
|
||||
through the `contractsProperties` method (for example, `contracts { contractsProperties([foo:"bar"]) }`),
|
||||
or through a system property or an environment variable.
|
||||
|
||||
[[gradle-consumer]]
|
||||
== Spring Cloud Contract Verifier on the Consumer Side
|
||||
|
||||
In a consuming service, you need to configure the Spring Cloud Contract Verifier plugin
|
||||
in exactly the same way as in the case of a provider. If you do not want to use Stub Runner,
|
||||
you need to copy the contracts stored in `src/contractTest/resources/contracts` and generate
|
||||
WireMock JSON stubs by using the following command:
|
||||
|
||||
====
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
./gradlew generateClientStubs
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: The `stubsOutputDir` option has to be set for stub generation to work.
|
||||
|
||||
When present, you can use JSON stubs in automated tests to consume a service. The
|
||||
following example shows how to do so:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
@ContextConfiguration(loader == SpringApplicationContextLoader, classes == Application)
|
||||
class LoanApplicationServiceSpec extends Specification {
|
||||
|
||||
@ClassRule
|
||||
@Shared
|
||||
WireMockClassRule wireMockRule == new WireMockClassRule()
|
||||
|
||||
@Autowired
|
||||
LoanApplicationService sut
|
||||
|
||||
def 'should successfully apply for loan'() {
|
||||
given:
|
||||
LoanApplication application =
|
||||
new LoanApplication(client: new Client(clientPesel: '12345678901'), amount: 123.123)
|
||||
when:
|
||||
LoanApplicationResult loanApplication == sut.loanApplication(application)
|
||||
then:
|
||||
loanApplication.loanApplicationStatus == LoanApplicationStatus.LOAN_APPLIED
|
||||
loanApplication.rejectionReason == null
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
In the preceding example, `LoanApplication` makes a call to the `FraudDetection` service.
|
||||
This request is handled by a WireMock server configured with stubs that were generated by
|
||||
Spring Cloud Contract Verifier.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
include::spring-cloud-contract.adoc[]
|
||||
@@ -1,11 +0,0 @@
|
||||
[legal]
|
||||
= Legal
|
||||
|
||||
{project-version}
|
||||
|
||||
Copyright © 2012-2020
|
||||
|
||||
Copies of this document may be made for your own use and for distribution to
|
||||
others, provided that you do not charge any fee for such copies and further
|
||||
provided that each copy contains this Copyright Notice, whether distributed in
|
||||
print or electronically.
|
||||
@@ -1,658 +0,0 @@
|
||||
= Maven Project
|
||||
include::_attributes.adoc[]
|
||||
|
||||
To learn how to set up the Maven project for Spring Cloud Contract Verifier, read the
|
||||
following sections:
|
||||
|
||||
* <<maven-add-plugin>>
|
||||
* <<maven-rest-assured>>
|
||||
* <<maven-snapshot-versions>>
|
||||
* <<maven-add-stubs>>
|
||||
* <<maven-run-plugin>>
|
||||
* <<maven-configure-plugin>>
|
||||
* <<maven-configuration-options>>
|
||||
* <<maven-single-base>>
|
||||
* <<maven-different-base>>
|
||||
* <<maven-invoking-generated-tests>>
|
||||
* <<maven-pushing-stubs-to-scm>>
|
||||
* <<maven-sts>>
|
||||
|
||||
You can also check the plugin's documentation link:../../spring-cloud-contract-maven-plugin/index.html[here].
|
||||
|
||||
[[maven-add-plugin]]
|
||||
== Adding the Maven Plugin
|
||||
|
||||
To add the Spring Cloud Contract BOM, include the following section in your `pom.xml` file:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{standalone_samples_path}/http-server/pom.xml[tags=contract_bom,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
Next, add the `Spring Cloud Contract Verifier` Maven plugin, as follows:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{standalone_samples_path}/http-server/pom.xml[tags=contract_maven_plugin,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
You can read more in the
|
||||
spring-cloud-contract-maven-plugin/index.html[Spring
|
||||
Cloud Contract Maven Plugin Documentation].
|
||||
|
||||
Sometimes, regardless of the picked IDE, you can see that the `target/generated-test-source` folder is not visible on the IDE's classpath. To ensure that it is always there, you can add the following entry to your `pom.xml`
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source</id>
|
||||
<phase>generate-test-sources</phase>
|
||||
<goals>
|
||||
<goal>add-test-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${project.build.directory}/generated-test-sources/contracts/</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
----
|
||||
====
|
||||
|
||||
[[maven-rest-assured]]
|
||||
== Maven and Rest Assured 2.0
|
||||
|
||||
By default, Rest Assured 3.x is added to the classpath. However, you can use Rest
|
||||
Assured 2.x by adding it to the plugins classpath, as follows:
|
||||
|
||||
====
|
||||
[source,groovy,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>
|
||||
<packageWithBaseClasses>com.example</packageWithBaseClasses>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-verifier</artifactId>
|
||||
<version>${spring-cloud-contract.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jayway.restassured</groupId>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
<version>2.5.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jayway.restassured</groupId>
|
||||
<artifactId>spring-mock-mvc</artifactId>
|
||||
<version>2.5.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
|
||||
<dependencies>
|
||||
<!-- all dependencies -->
|
||||
<!-- you can exclude rest-assured from spring-cloud-contract-verifier -->
|
||||
<dependency>
|
||||
<groupId>com.jayway.restassured</groupId>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
<version>2.5.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jayway.restassured</groupId>
|
||||
<artifactId>spring-mock-mvc</artifactId>
|
||||
<version>2.5.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
----
|
||||
====
|
||||
|
||||
That way, the plugin automatically sees that Rest Assured 2.x is present on the classpath
|
||||
and modifies the imports accordingly.
|
||||
|
||||
[[maven-snapshot-versions]]
|
||||
== Using Snapshot and Milestone Versions for Maven
|
||||
|
||||
To use Snapshot and Milestone versions, you have to add the following section to your
|
||||
`pom.xml`:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{standalone_samples_path}/http-server/pom.xml[tags=repos,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
[[maven-add-stubs]]
|
||||
== Adding stubs
|
||||
|
||||
By default, Spring Cloud Contract Verifier looks for stubs in the
|
||||
`src/test/resources/contracts` directory. The directory containing stub definitions is
|
||||
treated as a class name, and each stub definition is treated as a single test. We assume
|
||||
that it contains at least one directory to be used as the test class name. If there is more
|
||||
than one level of nested directories, all except the last one is used as the package name.
|
||||
Consider the following structure:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
src/test/resources/contracts/myservice/shouldCreateUser.groovy
|
||||
src/test/resources/contracts/myservice/shouldReturnUser.groovy
|
||||
----
|
||||
====
|
||||
|
||||
Given that structure, Spring Cloud Contract Verifier creates a test class named
|
||||
`defaultBasePackage.MyService` with two methods:
|
||||
|
||||
* `shouldCreateUser()`
|
||||
* `shouldReturnUser()`
|
||||
|
||||
[[maven-run-plugin]]
|
||||
== Run Plugin
|
||||
|
||||
The `generateTests` plugin goal is assigned to be invoked in the phase called
|
||||
`generate-test-sources`. If you want it to be part of your build process, you need not do
|
||||
anything. If you want only to generate tests, invoke the `generateTests` goal.
|
||||
|
||||
If you want to run stubs from Maven, call the `run` goal with the stubs to run as the `spring.cloud.contract.verifier.stubs` system property as follows:
|
||||
|
||||
[source,bash,indent=0]
|
||||
====
|
||||
mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:run \
|
||||
-Dspring.cloud.contract.verifier.stubs="com.acme:service-name"
|
||||
====
|
||||
|
||||
[[maven-configure-plugin]]
|
||||
== Configure plugin
|
||||
|
||||
To change the default configuration, you can add a `configuration` section to the plugin
|
||||
definition or the `execution` definition, as follows:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
<plugin>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>convert</goal>
|
||||
<goal>generateStubs</goal>
|
||||
<goal>generateTests</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<basePackageForTests>org.springframework.cloud.verifier.twitter.place</basePackageForTests>
|
||||
<baseClassForTests>org.springframework.cloud.verifier.twitter.place.BaseMockMvcSpec</baseClassForTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
----
|
||||
====
|
||||
|
||||
[[maven-configuration-options]]
|
||||
== Configuration Options
|
||||
|
||||
* `testMode`: Defines the mode for acceptance tests. By default, the mode is `MockMvc`,
|
||||
which is based on Spring's MockMvc. You can also change it to `WebTestClient`, `JaxRsClient`, or
|
||||
`Explicit` (for real HTTP calls).
|
||||
* `basePackageForTests`: Specifies the base package for all generated tests. If not set,
|
||||
the value is picked from the package of `baseClassForTests` and from `packageWithBaseClasses`.
|
||||
If neither of these values are set, the value is set to
|
||||
`org.springframework.cloud.contract.verifier.tests`.
|
||||
* `ruleClassForTests`: Specifies a rule that should be added to the generated test
|
||||
classes.
|
||||
* `baseClassForTests`: Creates a base class for all generated tests. By default, if you
|
||||
use Spock classes, the class is `spock.lang.Specification`.
|
||||
* `contractsDirectory`: Specifies a directory that contains contracts written with the
|
||||
Groovyn DSL. The default directory is `/src/test/resources/contracts`.
|
||||
* `generatedTestSourcesDir`: Specifies the test source directory where tests generated
|
||||
from the Groovy DSL should be placed. By default, its value is
|
||||
`$buildDir/generated-test-sources/contracts`.
|
||||
* `generatedTestResourcesDir`: Specifies the test resource directory for resources used by the generated tests.
|
||||
* `testFramework`: Specifies the target test framework to be used. Currently, Spock, JUnit 4 (`TestFramework.JUNIT`), and
|
||||
JUnit 5 are supported, with JUnit 4 being the default framework.
|
||||
* `packageWithBaseClasses`: Defines a package where all the base classes reside. This
|
||||
setting takes precedence over `baseClassForTests`. The convention is such that, if you
|
||||
have a contract under (for example) `src/test/resources/contract/foo/bar/baz/` and set
|
||||
the value of the `packageWithBaseClasses` property to `com.example.base`, Spring
|
||||
Cloud Contract Verifier assumes that there is a `BarBazBase` class under the
|
||||
`com.example.base` package. In other words, the system takes the last two parts of the
|
||||
package, if they exist, and forms a class with `Base` as a suffix.
|
||||
* `baseClassMappings`: Specifies a list of base class mappings that provide
|
||||
`contractPackageRegex` (which is checked against the package where the contract is
|
||||
located) and `baseClassFQN`( which maps to the fully qualified name of the base class for
|
||||
the matched contract). For example, if you have a contract under
|
||||
`src/test/resources/contract/foo/bar/baz/` and map the
|
||||
`.* -> com.example.base.BaseClass` property, the test class generated from these contracts
|
||||
extends `com.example.base.BaseClass`. This setting takes precedence over
|
||||
`packageWithBaseClasses` and `baseClassForTests`.
|
||||
* `contractsProperties`: A map that contains properties to be passed to Spring Cloud Contract
|
||||
components. Those properties might be used by (for example) built-in or custom Stub Downloaders.
|
||||
* `failOnNoContracts`: When enabled, will throw an exception when no contracts were found. Defaults to `true`.
|
||||
* `failOnInProgress`: If set to `true`, then, if any contracts that are in progress are found, they break the build. On the producer side, you need to be explicit about the fact that you have contracts in progress and take into consideration that you might be causing false positive test results on the consumer side. Defaults to `true`.
|
||||
* `incrementalContractTests`: When enabled, tests are created only when contracts have changed since last build. Defaults to `true`.
|
||||
* `incrementalContractStubs`: When enabled, stubs are created only when contracts have changed since last build. Defaults to `true`.
|
||||
* `incrementalContractStubsJar`: When enabled, stubs jar is created only when stubs have changed since last build. Defaults to `true`.
|
||||
*`httpPort` : HTTP port for the WireMock server that serves stubs. Currently `spring.cloud.contract.verifier.http.port` property works only when serving stubs from the directory. Otherwise, when providing stubs id, port have to be included in the id string.
|
||||
*`skip`: Set this to `true` to bypass the verifier execution.
|
||||
*`skipTestOnly`: Set this to `true` to bypass verifier test generation.
|
||||
*`stubs` : List of stubs to be downloaded and ran in a colon separated Ivy notation.
|
||||
*`minPort` : Specifies the minimal port at which the stub should start.
|
||||
*`maxPort` : Specifies the maximal port at which the stub should start.
|
||||
*`waitForKeyPressed` : Specifies if the plugin should wait for the user to press the key after starting the stubs.
|
||||
*`stubsClassifier`: Specifies the classifier used by stubs artifacts.
|
||||
|
||||
If you want to download your contract definitions from a Maven repository, you can use
|
||||
the following options:
|
||||
|
||||
* `contractDependency`: The contract dependency that contains all the packaged contracts.
|
||||
* `contractsPath`: The path to the concrete contracts in the JAR with packaged contracts.
|
||||
Defaults to `groupid/artifactid` where `gropuid` is slash separated.
|
||||
* `contractsMode`: Picks the mode in which stubs are found and registered.
|
||||
* `deleteStubsAfterTest`: If set to `false`, do not remove any downloaded
|
||||
contracts from temporary directories.
|
||||
* `contractsRepositoryUrl`: URL to a repository with the artifacts that have contracts. If it is not provided,
|
||||
use the current Maven ones.
|
||||
* `contractsRepositoryUsername`: The user name to be used to connect to the repo with contracts.
|
||||
* `contractsRepositoryPassword`: The password to be used to connect to the repo with contracts.
|
||||
* `contractsRepositoryProxyHost`: The proxy host to be used to connect to the repo with contracts.
|
||||
* `contractsRepositoryProxyPort`: The proxy port to be used to connect to the repo with contracts.
|
||||
|
||||
We cache only non-snapshot, explicitly provided versions (for example
|
||||
`+` or `1.0.0.BUILD-SNAPSHOT` do not get cached). By default, this feature is turned on.
|
||||
|
||||
The following list describes experimental features that you can turn on in the plugin:
|
||||
|
||||
* `convertToYaml`: Converts all DSLs to the declarative YAML format. This can be extremely useful when you use external libraries in your Groovy DSLs. By turning this feature on (by setting it to `true`), you need not add the library dependency on the consumer side.
|
||||
* `assertJsonSize`: You can check the size of JSON arrays in the generated tests. This feature is disabled by default.
|
||||
|
||||
[[maven-single-base]]
|
||||
== Single Base Class for All Tests
|
||||
|
||||
When using Spring Cloud Contract Verifier in the default (`MockMvc`), you need to create a base
|
||||
specification for all generated acceptance tests. In this class, you need to point to an
|
||||
endpoint, which should be verified. The following example shows how to do so:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
package org.mycompany.tests
|
||||
|
||||
import org.mycompany.ExampleSpringController
|
||||
import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc
|
||||
import spock.lang.Specification
|
||||
|
||||
class MvcSpec extends Specification {
|
||||
def setup() {
|
||||
RestAssuredMockMvc.standaloneSetup(new ExampleSpringController())
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
If necessary, you can also setup the whole context, as the following example shows:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
----
|
||||
import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SomeConfig.class, properties="some=property")
|
||||
public abstract class BaseTestClass {
|
||||
|
||||
@Autowired
|
||||
WebApplicationContext context;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
RestAssuredMockMvc.webAppContextSetup(this.context);
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
If you use `EXPLICIT` mode, you can use a base class to initialize the whole tested app,
|
||||
similar to what you might do in regular integration tests. The following example shows
|
||||
how to do so:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
----
|
||||
import io.restassured.RestAssured;
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SomeConfig.class, properties="some=property")
|
||||
public abstract class BaseTestClass {
|
||||
|
||||
@LocalServerPort
|
||||
int port;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
RestAssured.baseURI = "http://localhost:" + this.port;
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
If you use the `JAXRSCLIENT` mode, this base class should also contain a `protected WebTarget webTarget` field. Right
|
||||
now, the only way to test the JAX-RS API is to start a web server.
|
||||
|
||||
[[maven-different-base]]
|
||||
== Using 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:
|
||||
|
||||
* Follow a convention by providing a value for `packageWithBaseClasses`
|
||||
* Provide explicit mapping with `baseClassMappings`
|
||||
|
||||
=== By Convention
|
||||
|
||||
The convention is such that if you have a contract under (for example)
|
||||
`src/test/resources/contract/foo/bar/baz/` and set the value of the
|
||||
`packageWithBaseClasses` property to `com.example.base`, then Spring Cloud Contract
|
||||
Verifier assumes that there is a `BarBazBase` class under the `com.example.base` package.
|
||||
In other words, the system takes the last two parts of the package, if they exist, and
|
||||
forms a class with a `Base` suffix. This rule takes precedence over `baseClassForTests`.
|
||||
The following example shows how it works in the `contracts` closure:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{plugins_path}/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/pom.xml[tags=convention,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
=== By Mapping
|
||||
|
||||
You can manually map a regular expression of the contract's package to the fully qualified
|
||||
name of the base class for the matched contract. You have to provide a list called
|
||||
`baseClassMappings` that consists of `baseClassMapping` objects that each take a
|
||||
`contractPackageRegex` to `baseClassFQN` mapping. Consider the following example:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{plugins_path}/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/pom.xml[tags=mapping,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
Assume that you have contracts under these two locations:
|
||||
|
||||
* `src/test/resources/contract/com/`
|
||||
* `src/test/resources/contract/foo/`
|
||||
|
||||
By providing the `baseClassForTests`, we have a fallback in case mapping did not succeed.
|
||||
(You can also provide the `packageWithBaseClasses` as a fallback.) That way, the tests
|
||||
generated from `src/test/resources/contract/com/` contracts extend the
|
||||
`com.example.ComBase`, whereas the rest of the tests extend `com.example.FooBase`.
|
||||
|
||||
[[maven-invoking-generated-tests]]
|
||||
== Invoking Generated Tests
|
||||
|
||||
The Spring Cloud Contract Maven Plugin generates verification code in a directory called
|
||||
`/generated-test-sources/contractVerifier` and attaches this directory to `testCompile`
|
||||
goal.
|
||||
|
||||
For Groovy Spock code, you can use the following:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmavenplus</groupId>
|
||||
<artifactId>gmavenplus-plugin</artifactId>
|
||||
<version>1.5</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<testSources>
|
||||
<testSource>
|
||||
<directory>${project.basedir}/src/test/groovy</directory>
|
||||
<includes>
|
||||
<include>**/*.groovy</include>
|
||||
</includes>
|
||||
</testSource>
|
||||
<testSource>
|
||||
<directory>${project.build.directory}/generated-test-sources/contractVerifier</directory>
|
||||
<includes>
|
||||
<include>**/*.groovy</include>
|
||||
</includes>
|
||||
</testSource>
|
||||
</testSources>
|
||||
</configuration>
|
||||
</plugin>
|
||||
----
|
||||
====
|
||||
|
||||
To ensure that the provider side is compliant with defined contracts, you need to invoke
|
||||
`mvn generateTest test`.
|
||||
|
||||
[[maven-pushing-stubs-to-scm]]
|
||||
== Pushing Stubs to SCM
|
||||
|
||||
If you use the SCM (Source Control Management) repository to keep the contracts and
|
||||
stubs, you might want to automate the step of pushing stubs to
|
||||
the repository. To do that, you can add the `pushStubsToScm`
|
||||
goal. The following example shows how to do so:
|
||||
|
||||
====
|
||||
[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>git://https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git</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>
|
||||
<version>${project.version}</version>
|
||||
</contractDependency>
|
||||
|
||||
<!-- The contracts mode can't be classpath -->
|
||||
<contractsMode>REMOTE</contractsMode>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<!-- By default we will not push the stubs back to SCM,
|
||||
you have to explicitly add it as a goal -->
|
||||
<goal>pushStubsToScm</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
----
|
||||
====
|
||||
|
||||
Under <<scm-stub-downloader>>, you can find all possible
|
||||
configuration options that you can pass through
|
||||
the `<configuration><contractsProperties>` map, a system property,
|
||||
or an environment variable. For instance, you could specify a concrete branch to checkout, instead of the default one
|
||||
|
||||
====
|
||||
[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>git://https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git</contractsRepositoryUrl>
|
||||
<contractsProperties>
|
||||
<git.branch>another_branch</git.branch>
|
||||
</contractsProperties>
|
||||
|
||||
<!-- 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>
|
||||
<version>${project.version}</version>
|
||||
</contractDependency>
|
||||
|
||||
<!-- The contracts mode can't be classpath -->
|
||||
<contractsMode>REMOTE</contractsMode>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<!-- By default we will not push the stubs back to SCM,
|
||||
you have to explicitly add it as a goal -->
|
||||
<goal>pushStubsToScm</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
[[maven-sts]]
|
||||
== Maven Plugin and STS
|
||||
|
||||
The following image shows an exception that you may see when you use STS:
|
||||
|
||||
image::{github-raw}/docs/src/main/asciidoc/images/sts_exception.png[STS Exception]
|
||||
|
||||
When you click on the error marker, you should see something like the following:
|
||||
|
||||
====
|
||||
[source,bash]
|
||||
----
|
||||
plugin:1.1.0.M1:convert:default-convert:process-test-resources) org.apache.maven.plugin.PluginExecutionException: Execution default-convert of goal org.springframework.cloud:spring-
|
||||
cloud-contract-maven-plugin:1.1.0.M1:convert failed. at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:145) at
|
||||
org.eclipse.m2e.core.internal.embedder.MavenImpl.execute(MavenImpl.java:331) at org.eclipse.m2e.core.internal.embedder.MavenImpl$11.call(MavenImpl.java:1362) at
|
||||
...
|
||||
org.eclipse.core.internal.jobs.Worker.run(Worker.java:55) Caused by: java.lang.NullPointerException at
|
||||
org.eclipse.m2e.core.internal.builder.plexusbuildapi.EclipseIncrementalBuildContext.hasDelta(EclipseIncrementalBuildContext.java:53) at
|
||||
org.sonatype.plexus.build.incremental.ThreadBuildContext.hasDelta(ThreadBuildContext.java:59) at
|
||||
----
|
||||
====
|
||||
|
||||
To fix this issue, provide the following section in your `pom.xml`:
|
||||
|
||||
====
|
||||
[source,xml]
|
||||
----
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings
|
||||
only. It has no influence on the Maven build itself. -->
|
||||
<plugin>
|
||||
<groupId>org.eclipse.m2e</groupId>
|
||||
<artifactId>lifecycle-mapping</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<configuration>
|
||||
<lifecycleMappingMetadata>
|
||||
<pluginExecutions>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
|
||||
<versionRange>[1.0,)</versionRange>
|
||||
<goals>
|
||||
<goal>convert</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<execute />
|
||||
</action>
|
||||
</pluginExecution>
|
||||
</pluginExecutions>
|
||||
</lifecycleMappingMetadata>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
----
|
||||
====
|
||||
|
||||
== Maven Plugin with Spock Tests
|
||||
|
||||
You can select the http://spockframework.org/[Spock Framework] for creating and running the auto-generated contract
|
||||
verification tests with both Maven and Gradle. However, while using Gradle is straightforward,
|
||||
in Maven, you need some additional setup in order to make the tests compile and execute properly.
|
||||
|
||||
First of all, you must use a plugin, such as the https://github.com/groovy/GMavenPlus[GMavenPlus] plugin,
|
||||
to add Groovy to your project. In GMavenPlus plugin, you need to explicitly set test sources, including both the
|
||||
path where your base test classes are defined and the path were the generated contract tests are added.
|
||||
The following example shows how to do so:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{samples_url}/producer_with_spock/pom.xml[tags=gmavenplus-setup,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
If you uphold the Spock convention of ending the test class names with `Spec`, you also need to adjust your Maven
|
||||
Surefire plugin setup, as the following example shows:
|
||||
|
||||
====
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{samples_url}/producer_with_spock/pom.xml[tags=spock-surefire-setup,indent=0]
|
||||
----
|
||||
====
|
||||
@@ -1,40 +0,0 @@
|
||||
[[features]]
|
||||
= Spring Cloud Contract Features
|
||||
include::_attributes.adoc[]
|
||||
|
||||
This section dives into the details of {project-full-name}. Here you can learn about the key
|
||||
features that you may want to use and customize. If you have not already done so, you
|
||||
might want to read the "<<getting-started.adoc#getting-started>>" and
|
||||
"<<using.adoc#using>>" sections, so that you have a good grounding in the
|
||||
basics.
|
||||
|
||||
include::_project-features-contract.adoc[]
|
||||
|
||||
include::_project-features-flows.adoc[]
|
||||
|
||||
include::_project-features-messaging.adoc[]
|
||||
|
||||
include::_project-features-stubrunner.adoc[]
|
||||
|
||||
include::_project-features-wiremock.adoc[]
|
||||
|
||||
[[features-build-tools]]
|
||||
== Build Tools Integration
|
||||
|
||||
You can run test generation and stub invokation in various ways. The most common ones are
|
||||
as follows:
|
||||
|
||||
* link:maven-project.html[Maven]
|
||||
* link:gradle-project.html[Gradle]
|
||||
* link:docker-project.html[Docker]
|
||||
|
||||
[[features-whats-next]]
|
||||
== What to Read Next
|
||||
|
||||
If you want to learn more about any of the classes discussed in this section, you can browse the
|
||||
{github-code}[source code directly]. If you have specific questions, see the
|
||||
<<howto.adoc#howto, how-to>> section.
|
||||
|
||||
If you are comfortable with {project-full-name}'s core features, you can continue on and read
|
||||
about
|
||||
<<advanced.adoc#advanced.html, {project-full-name}'s advanced features>>.
|
||||
@@ -1,103 +0,0 @@
|
||||
== On the Producer Side
|
||||
|
||||
To start working with Spring Cloud Contract, you can add files with REST or messaging contracts expressed in either Groovy DSL or YAML to the contracts directory, which is set by the contractsDslDir property. By default, it is $rootDir/src/test/resources/contracts.
|
||||
|
||||
Then you can add the Spring Cloud Contract Verifier dependency and plugin to your build file, as the following example shows:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-contract-verifier</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
The following listing shows how to add the plugin, which should go in the build/plugins portion of the file:
|
||||
|
||||
```xml
|
||||
<plugin>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
|
||||
<version>${spring-cloud-contract.version}</version>
|
||||
<extensions>true</extensions>
|
||||
</plugin>
|
||||
```
|
||||
|
||||
Running `./mvnw clean install` automatically generates tests that verify the application compliance with the added contracts. By default, the tests get generated under `org.springframework.cloud.contract.verifier.tests`.
|
||||
|
||||
As the implementation of the functionalities described by the contracts is not yet present, the tests fail.
|
||||
|
||||
To make them pass, you must add the correct implementation of either handling HTTP requests or messages. Also, you must add a base test class for auto-generated tests to the project. This class is extended by all the auto-generated tests, and it should contain all the setup information necessary to run them (for example `RestAssuredMockMvc` controller setup or messaging test setup).
|
||||
|
||||
The following example, from pom.xml, shows how to specify the base test class:
|
||||
|
||||
```xml
|
||||
<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>
|
||||
<baseClassForTests>com.example.contractTest.BaseTestClass</baseClassForTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
```
|
||||
|
||||
INFO: The baseClassForTests element lets you specify your base test class. It must be a child of a configuration element within spring-cloud-contract-maven-plugin.
|
||||
|
||||
Once the implementation and the test base class are in place, the tests pass, and both the application and the stub artifacts are built and installed in the local Maven repository. You can now merge the changes, and you can publish both the application and the stub artifacts in an online repository.
|
||||
|
||||
== On the Consumer Side
|
||||
|
||||
You can use Spring Cloud Contract Stub Runner in the integration tests to get a running WireMock instance or messaging route that simulates the actual service.
|
||||
|
||||
To do so, add the dependency to Spring Cloud Contract Stub Runner, as the following example shows:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
You can get the Producer-side stubs installed in your Maven repository in either of two ways:
|
||||
|
||||
By checking out the Producer side repository and adding contracts and generating the stubs by running the following commands:
|
||||
|
||||
```bash
|
||||
$ cd local-http-server-repo
|
||||
$ ./mvnw clean install -DskipTests
|
||||
```
|
||||
|
||||
The tests are being skipped because the producer-side contract implementation is not in place yet, so the automatically-generated contract tests fail.
|
||||
|
||||
By getting already-existing producer service stubs from a remote repository. To do so, pass the stub artifact IDs and artifact repository URL as Spring Cloud Contract Stub Runner properties, as the following example shows:
|
||||
|
||||
```yml
|
||||
stubrunner:
|
||||
ids: 'com.example:http-server-dsl:+:stubs:8080'
|
||||
repositoryRoot: https://repo.spring.io/libs-snapshot
|
||||
```
|
||||
|
||||
Now you can annotate your test class with `@AutoConfigureStubRunner`. In the annotation, provide the group-id and artifact-id values for Spring Cloud Contract Stub Runner to run the collaborators' stubs for you, as the following example shows:
|
||||
|
||||
```java
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
|
||||
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
|
||||
stubsMode = StubRunnerProperties.StubsMode.LOCAL)
|
||||
public class LoanApplicationServiceTests {
|
||||
```
|
||||
|
||||
Use the `REMOTE` stubsMode when downloading stubs from an online repository and `LOCAL` for offline work.
|
||||
|
||||
Now, in your integration test, you can receive stubbed versions of HTTP responses or messages that are expected to be emitted by the collaborator service.
|
||||
@@ -1,69 +0,0 @@
|
||||
Spring Cloud Contract is an umbrella project holding solutions that help users in successfully implementing the Consumer Driven Contracts approach. Currently Spring Cloud Contract consists of the Spring Cloud Contract Verifier project.
|
||||
|
||||
Spring Cloud Contract Verifier is a tool that enables Consumer Driven Contract (CDC) development of JVM-based applications. It is shipped with Contract Definition Language (DSL) written in Groovy or YAML. Contract definitions are used to produce following resources:
|
||||
|
||||
* by default JSON stub definitions to be used by WireMock (HTTP Server Stub) when doing integration testing on the client code (client tests). Test code must still be written by hand, test data is produced by Spring Cloud Contract Verifier.
|
||||
|
||||
* Messaging routes if you’re using one. We’re integrating with Spring Integration, Spring Cloud Stream and Apache Camel. You can however set your own integrations if you want to.
|
||||
|
||||
* Acceptance tests (by default in JUnit or Spock) used to verify if server-side implementation of the API is compliant with the contract (server tests). Full test is generated by Spring Cloud Contract Verifier.
|
||||
|
||||
Spring Cloud Contract Verifier moves TDD to the level of software architecture.
|
||||
|
||||
To see how Spring Cloud Contract supports other languages just check out https://spring.io/blog/2018/02/13/spring-cloud-contract-in-a-polyglot-world[this blog post].
|
||||
|
||||
## Features
|
||||
|
||||
When trying to test an application that communicates with other services then we could do one of two things:
|
||||
|
||||
* deploy all microservices and perform end to end tests
|
||||
|
||||
* mock other microservices in unit / integration tests
|
||||
|
||||
Both have their advantages but also a lot of disadvantages. Let’s focus on the latter.
|
||||
Deploy all microservices and perform end to end tests
|
||||
|
||||
Advantages:
|
||||
|
||||
* simulates production
|
||||
|
||||
* tests real communication between services
|
||||
|
||||
Disadvantages:
|
||||
|
||||
* to test one microservice we would have to deploy 6 microservices, a couple of databases etc.
|
||||
|
||||
* the environment where the tests would be conducted would be locked for a single suite of tests (i.e. nobody else would be able to run the tests in the meantime).
|
||||
|
||||
* long to run
|
||||
|
||||
* very late feedback
|
||||
|
||||
* extremely hard to debug
|
||||
|
||||
Mock other microservices in unit / integration tests
|
||||
|
||||
Advantages:
|
||||
|
||||
* very fast feedback
|
||||
|
||||
* no infrastructure requirements
|
||||
|
||||
Disadvantages:
|
||||
|
||||
* the implementor of the service creates stubs thus they might have nothing to do with the reality
|
||||
|
||||
* you can go to production with passing tests and failing production
|
||||
|
||||
To solve the aforementioned issues Spring Cloud Contract Verifier with Stub Runner were created. Their main idea is to give you very fast feedback, without the need to set up the whole world of microservices.
|
||||
|
||||
Spring Cloud Contract Verifier features:
|
||||
|
||||
* ensure that HTTP / Messaging stubs (used when developing the client) are doing exactly what actual server-side implementation will do
|
||||
|
||||
* promote acceptance test driven development method and Microservices architectural style
|
||||
|
||||
* to provide a way to publish changes in contracts that are immediately visible on both sides of the communication
|
||||
|
||||
* to generate boilerplate test code used on the server side
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
[[spring-cloud-contract-reference-documentation]]
|
||||
= Spring Cloud Contract Reference Documentation
|
||||
Adam Dudczak, Mathias Düsterhöft, Marcin Grzejszczak, Dennis Kieselhorst, Jakub Kubryński, Karol Lassak, Olga Maciaszek-Sharma, Mariusz Smykuła, Dave Syer, Jay Bryant
|
||||
|
||||
:docinfo: shared
|
||||
include::_attributes.adoc[]
|
||||
|
||||
The reference documentation consists of the following sections:
|
||||
|
||||
[horizontal]
|
||||
<<legal.adoc#legal-information,Legal>> :: Legal information.
|
||||
<<documentation-overview.adoc#contract-documentation,Documentation Overview>> :: About the Documentation, Getting Help, First Steps, and more.
|
||||
<<getting-started.adoc#getting-started,Getting Started>> :: Introducing {project-full-name}, Developing Your First {project-full-name}-based Application
|
||||
<<using.adoc#using,Using {project-full-name}>> :: {project-full-name} usage examples and workflows.
|
||||
<<project-features.adoc#features,{project-full-name} Features>> :: Contract DSL, Messaging, Spring Cloud Contract Stub Runner, and Spring Cloud Contract WireMock.
|
||||
<<project-features.adoc#features-build-tools,Build Tools>> :: Maven Plugin, Gradle Plugin, and Docker.
|
||||
<<howto.adoc#howto,"`How-to`" Guides>> :: Stubs versioning, Debugging, and more.
|
||||
<<appendix.adoc#appendix,Appendices>> :: Properties, Metadata, Configuration, Dependencies, and more.
|
||||
@@ -1,868 +0,0 @@
|
||||
[[using]]
|
||||
= Using Spring Cloud Contract
|
||||
include::_attributes.adoc[]
|
||||
|
||||
This section goes into more detail about how you should use {project-full-name}. It covers topics
|
||||
such as flows of how to work with {project-full-name}. We also
|
||||
cover some {project-full-name} best practices.
|
||||
|
||||
If you are starting out with {project-full-name}, you should probably read the
|
||||
<<getting-started.adoc#getting-started, Getting Started>> guide before diving into this
|
||||
section.
|
||||
|
||||
[[flows-provider-nexus]]
|
||||
== Provider Contract Testing with Stubs in Nexus or Artifactory
|
||||
|
||||
You can check the <<getting-started.adoc#getting-started-first-application, Developing Your First Spring Cloud Contract based application>> link to see the provider contract testing with stubs in the Nexus or Artifactory flow.
|
||||
|
||||
[[flows-provider-git]]
|
||||
== Provider Contract Testing with Stubs in Git
|
||||
|
||||
In this flow, we perform the provider contract testing (the producer has no knowledge of how consumers use their API). The stubs are uploaded to a separate repository (they are not uploaded to Artifactory or Nexus).
|
||||
|
||||
=== Prerequisites
|
||||
|
||||
Before testing provider contracts with stubs in git, you must provide a git repository
|
||||
that contains all the stubs for each producer. For an example of such a project, see
|
||||
{samples_code}/contract_git[this samples ] or {samples_code}/contract_git[this sample].
|
||||
As a result of pushing stubs there, the repository has the following structure:
|
||||
|
||||
====
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
$ tree .
|
||||
└── META-INF
|
||||
└── folder.with.group.id.as.its.name
|
||||
└── folder-with-artifact-id
|
||||
└── folder-with-version
|
||||
├── contractA.groovy
|
||||
├── contractB.yml
|
||||
└── contractC.groovy
|
||||
|
||||
----
|
||||
====
|
||||
|
||||
You must also provide consumer code that has Spring Cloud Contract Stub Runner set up. For
|
||||
an example of such a project, see {samples_code}/consumer[this sample] and search for a
|
||||
`BeerControllerGitTest` test. You must also provide producer code that has Spring Cloud
|
||||
Contract set up, together with a plugin. For an example of such a project, see
|
||||
{samples_code}/producer_with_empty_git[this sample].
|
||||
|
||||
[[flows-provider-git-flow]]
|
||||
=== The Flow
|
||||
|
||||
The flow looks exactly as the one presented in
|
||||
<<getting-started.adoc#getting-started-first-application, Developing Your First Spring Cloud Contract based application>>,
|
||||
but the `Stub Storage` implementation is a git repository.
|
||||
|
||||
You can read more about setting up a git repository and setting consumer and producer side
|
||||
in the <<howto.adoc#how-to-use-git-as-storage,How To page>> of the documentation.
|
||||
|
||||
[[flows-provider-git-consumer]]
|
||||
=== Consumer setup
|
||||
|
||||
In order to fetch the stubs from a git repository instead of Nexus or Artifactory, you
|
||||
need to use the `git` protocol in the URL of the `repositoryRoot` property in Stub Runner.
|
||||
The following example shows how to set it up:
|
||||
|
||||
====
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Annotation
|
||||
----
|
||||
@AutoConfigureStubRunner(
|
||||
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
|
||||
repositoryRoot = "git://git@github.com:spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git",
|
||||
ids = "com.example:artifact-id:0.0.1")
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.JUnit 4 Rule
|
||||
----
|
||||
@Rule
|
||||
public StubRunnerRule rule = new StubRunnerRule()
|
||||
.downloadStub("com.example","artifact-id", "0.0.1")
|
||||
.repoRoot("git://git@github.com:spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git")
|
||||
.stubsMode(StubRunnerProperties.StubsMode.REMOTE);
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.JUnit 5 Extension
|
||||
----
|
||||
@RegisterExtension
|
||||
public StubRunnerExtension stubRunnerExtension = new StubRunnerExtension()
|
||||
.downloadStub("com.example","artifact-id", "0.0.1")
|
||||
.repoRoot("git://git@github.com:spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git")
|
||||
.stubsMode(StubRunnerProperties.StubsMode.REMOTE);
|
||||
----
|
||||
====
|
||||
|
||||
[[flows-provider-git-producer]]
|
||||
=== Setting up the Producer
|
||||
|
||||
To push the stubs to a git repository instead of Nexus or Artifactory, you need
|
||||
to use the `git` protocol in the URL of the plugin setup. Also you need to explicitly tell
|
||||
the plugin to push the stubs at the end of the build process. The following examples show
|
||||
how to do so in both Maven and Gradle:
|
||||
|
||||
====
|
||||
[source,xml,indent=0,role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<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>git://git://git@github.com:spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git</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>
|
||||
<version>${project.version}</version>
|
||||
</contractDependency>
|
||||
|
||||
<!-- The contracts mode can't be classpath -->
|
||||
<contractsMode>REMOTE</contractsMode>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<!-- By default we will not push the stubs back to SCM,
|
||||
you have to explicitly add it as a goal -->
|
||||
<goal>pushStubsToScm</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
contracts {
|
||||
// We want to pick contracts from a Git repository
|
||||
contractDependency {
|
||||
stringNotation = "${project.group}:${project.name}:${project.version}"
|
||||
}
|
||||
/*
|
||||
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
|
||||
*/
|
||||
contractRepository {
|
||||
repositoryUrl = "git://git://git@github.com:spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git"
|
||||
}
|
||||
// The mode can't be classpath
|
||||
contractsMode = "REMOTE"
|
||||
// Base class mappings etc.
|
||||
}
|
||||
|
||||
/*
|
||||
In this scenario we want to publish stubs to SCM whenever
|
||||
the `publish` task is run
|
||||
*/
|
||||
publish.dependsOn("publishStubsToScm")
|
||||
----
|
||||
====
|
||||
|
||||
You can read more about setting up a git repository in the
|
||||
<<howto.adoc#how-to-use-git-as-storage,How To section>> of the documentation.
|
||||
|
||||
[[flows-cdc-contracts-producer]]
|
||||
== Consumer Driven Contracts with Contracts on the Producer Side
|
||||
|
||||
See <<getting-started.adoc#getting-started-cdc, Step-by-step Guide to Consumer Driven
|
||||
Contracts (CDC) with Contracts on the Producer Side>> to see the Consumer Driven Contracts
|
||||
with contracts on the producer side flow.
|
||||
|
||||
[[flows-cdc-contracts-external]]
|
||||
== Consumer Driven Contracts with Contracts in an External Repository
|
||||
|
||||
In this flow, we perform Consumer Driven Contract testing. The contract definitions are
|
||||
stored in a separate repository.
|
||||
|
||||
=== Prerequisites
|
||||
|
||||
To use consumer-driven contracts with the contracts held in an external repository, you need to set up a git repository that:
|
||||
|
||||
* Contains all the contract definitions for each producer.
|
||||
* Can package the contract definitions in a JAR.
|
||||
* For each contract producer, contains a way (for example, `pom.xml`) to install stubs
|
||||
locally through the Spring Cloud Contract Plugin (SCC Plugin).
|
||||
|
||||
For more information, see the <<howto.adoc#how-to-common-repo-with-contracts, How To section>>,
|
||||
where we describe how to set up such a repository.
|
||||
For an example of such a project, see {samples_code}/beer_contracts[this sample].
|
||||
|
||||
You also need consumer code that has Spring Cloud Contract Stub Runner set up.
|
||||
For an example of such a project, see {samples_code}/consumer[this sample].
|
||||
You also need producer code that has Spring Cloud Contract set up, together with a plugin.
|
||||
For an example of such a project, see {samples_code}/producer_with_external_contracts[this sample].
|
||||
The stub storage is Nexus or Artifactory.
|
||||
|
||||
At a high level, the flow is as follows:
|
||||
|
||||
. The consumer works with the contract definitions from the separate repository.
|
||||
. Once the consumer's work is done, a branch with working code is created on the consumer
|
||||
side, and a pull request is made to the separate repository that holds the contract definitions.
|
||||
. The producer takes over the pull request to the separate repository with contract
|
||||
definitions and installs the JAR with all contracts locally.
|
||||
. The producer generates tests from the locally stored JAR and writes the missing
|
||||
implementation to make the tests pass.
|
||||
. Once the producer's work is done, the pull request to the repository that holds the
|
||||
contract definitions is merged.
|
||||
. After the CI tool builds the repository with the contract definitions and the JAR with
|
||||
contract definitions gets uploaded to Nexus or Artifactory, the producer can merge its branch.
|
||||
. Finally, the consumer can switch to working online to fetch stubs of the producer from a
|
||||
remote location, and the branch can be merged to master.
|
||||
|
||||
[[flows-cdc-contracts-external-consumer]]
|
||||
=== Consumer Flow
|
||||
|
||||
The consumer:
|
||||
|
||||
. Writes a test that would send a request to the producer.
|
||||
+
|
||||
The test fails due to no server being present.
|
||||
. Clones the repository that holds the contract definitions.
|
||||
. Sets up the requirements as contracts under the folder, with the consumer name as a subfolder of the producer.
|
||||
+
|
||||
For example, for a producer named `producer` and a consumer named `consumer`, the contracts would be stored under `src/main/resources/contracts/producer/consumer/`)
|
||||
. Once the contracts are defined, installs the producer stubs to local storage, as the following example shows:
|
||||
+
|
||||
====
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
$ cd src/main/resource/contracts/producer
|
||||
$ ./mvnw clean install
|
||||
----
|
||||
====
|
||||
. Sets up Spring Cloud Contract (SCC) Stub Runner in the consumer tests, to:
|
||||
* Fetch the producer stubs from local storage.
|
||||
* Work in the stubs-per-consumer mode (this enables consumer driven contracts mode).
|
||||
+
|
||||
The SCC Stub Runner:
|
||||
* Fetches the producer stubs.
|
||||
* Runs an in-memory HTTP server stub with the producer stubs.
|
||||
Now your test communicates with the HTTP server stub, and your tests pass.
|
||||
* Creates a pull request to the repository with contract definitions, with the new contracts for the producer.
|
||||
* Branches your consumer code, until the producer team has merged their code.
|
||||
|
||||
The following UML diagram shows the consumer flow:
|
||||
|
||||
[plantuml, flow-overview-consumer-cdc-external-consumer, png]
|
||||
----
|
||||
"Consumer"->"Repo\nwith\ncontracts": clone
|
||||
"Repo\nwith\ncontracts"->"Repo\nwith\ncontracts\nclone": cloned
|
||||
"Consumer"->"Repo\nwith\ncontracts\nclone": create contract\ndefinitions of\nthe [Producer]
|
||||
"Repo\nwith\ncontracts\nclone"->"Local storage": install [Producer]\nstubs locally
|
||||
"Consumer"->"Consumer\nBuild": run tests
|
||||
"Consumer\nBuild"->"SCC\nStub Runner": Run [Producer] stubs
|
||||
"SCC\nStub Runner"->"Local storage": fetch [Producer] stubs
|
||||
"SCC\nStub Runner"->"Producer stub": stub is running
|
||||
"Consumer\nBuild"->"Producer stub": send a request\nin the tests
|
||||
"Producer stub"->"Consumer\nBuild": send a response
|
||||
"Consumer\nBuild"->"Consumer": the tests are passing
|
||||
"Consumer"->"Repo\nwith\ncontracts\nclone": send a pull request
|
||||
"Repo\nwith\ncontracts\nclone"->"Repo\nwith\ncontracts": pull request sent
|
||||
"Consumer"->"Consumer": branch the code
|
||||
----
|
||||
|
||||
[[flows-cdc-contracts-external-producer]]
|
||||
=== Producer Flow
|
||||
|
||||
The producer:
|
||||
|
||||
. Takes over the pull request to the repository with contract definitions. You can do it
|
||||
from the command line, as follows
|
||||
+
|
||||
====
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
$ git checkout -b the_branch_with_pull_request master
|
||||
git pull https://github.com/user_id/project_name.git the_branch_with_pull_request
|
||||
----
|
||||
====
|
||||
. Installs the contract definitions, as follows
|
||||
+
|
||||
====
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
$ ./mvnw clean install
|
||||
----
|
||||
====
|
||||
. Sets up the plugin to fetch the contract definitions from a JAR instead of from
|
||||
`src/test/resources/contracts`, as follows:
|
||||
+
|
||||
====
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<plugin>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
|
||||
<version>${spring-cloud-contract.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<!-- We want to use the JAR with contracts with the following coordinates -->
|
||||
<contractDependency>
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>beer-contracts</artifactId>
|
||||
</contractDependency>
|
||||
<!-- The JAR with contracts should be taken from Maven local -->
|
||||
<contractsMode>LOCAL</contractsMode>
|
||||
<!-- ... additional configuration -->
|
||||
</configuration>
|
||||
</plugin>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
contracts {
|
||||
// We want to use the JAR with contracts with the following coordinates
|
||||
// group id `com.example`, artifact id `beer-contracts`, LATEST version and NO classifier
|
||||
contractDependency {
|
||||
stringNotation = 'com.example:beer-contracts:+:'
|
||||
}
|
||||
// The JAR with contracts should be taken from Maven local
|
||||
contractsMode = "LOCAL"
|
||||
// Additional configuration
|
||||
}
|
||||
----
|
||||
====
|
||||
. Runs the build to generate tests and stubs, as follows:
|
||||
+
|
||||
====
|
||||
[source,bash,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
./mvnw clean install
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
./gradlew clean build
|
||||
----
|
||||
====
|
||||
. Writes the missing implementation, to make the tests pass.
|
||||
. Merges the pull request to the repository with contract definitions, as follows:
|
||||
+
|
||||
====
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
$ git commit -am "Finished the implementation to make the contract tests pass"
|
||||
$ git checkout master
|
||||
$ git merge --no-ff the_branch_with_pull_request
|
||||
$ git push origin master
|
||||
----
|
||||
====
|
||||
+
|
||||
The CI system builds the project with the contract definitions and uploads the JAR with
|
||||
the contract definitions to Nexus or Artifactory.
|
||||
. Switches to working remotely.
|
||||
. Sets up the plugin so that the contract definitions are no longer taken from the local
|
||||
storage but from a remote location, as follows:
|
||||
+
|
||||
====
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<plugin>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
|
||||
<version>${spring-cloud-contract.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<!-- We want to use the JAR with contracts with the following coordinates -->
|
||||
<contractDependency>
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>beer-contracts</artifactId>
|
||||
</contractDependency>
|
||||
<!-- The JAR with contracts should be taken from a remote location -->
|
||||
<contractsMode>REMOTE</contractsMode>
|
||||
<!-- ... additional configuration -->
|
||||
</configuration>
|
||||
</plugin>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
contracts {
|
||||
// We want to use the JAR with contracts with the following coordinates
|
||||
// group id `com.example`, artifact id `beer-contracts`, LATEST version and NO classifier
|
||||
contractDependency {
|
||||
stringNotation = 'com.example:beer-contracts:+:'
|
||||
}
|
||||
// The JAR with contracts should be taken from a remote location
|
||||
contractsMode = "REMOTE"
|
||||
// Additional configuration
|
||||
}
|
||||
----
|
||||
====
|
||||
. Merges the producer code with the new implementation.
|
||||
. The CI system:
|
||||
** Builds the project.
|
||||
** Generates tests, stubs, and the stub JAR.
|
||||
** Uploads the artifact with the application and the stubs to Nexus or Artifactory.
|
||||
|
||||
The following UML diagram shows the producer process:
|
||||
|
||||
[plantuml, flow-overview-consumer-cdc-external-producer, png]
|
||||
----
|
||||
"Producer"->"Repo\nwith\ncontracts": take over the pull request
|
||||
"Producer"->"Repo\nwith\ncontracts": install the contract\ndefinitions JAR
|
||||
"Repo\nwith\ncontracts"->"Local storage": install the\ncontract definitions\nJAR locally
|
||||
"Local storage"->"Repo\nwith\ncontracts": contract definitions\nJAR installed
|
||||
"Producer"->"Producer\nBuild": run build
|
||||
"Producer\nBuild"->"SCC\nPlugin": generate tests,\nstubs\nand stub jar
|
||||
"SCC\nPlugin"->"Local storage": fetch the contract definitions
|
||||
"Local storage"->"SCC\nPlugin": contract definitions found
|
||||
"SCC\nPlugin"->"SCC\nPlugin": generate tests
|
||||
"Producer\nBuild"->"Producer\nBuild": run the\ngenerated tests
|
||||
"Producer\nBuild"->"Producer": the tests failed to pass
|
||||
"Producer"->"Producer": write the missing implementation
|
||||
"Producer"->"Producer\nBuild": run the build again
|
||||
"Producer\nBuild"->"Producer\nBuild": fetch the contract definitions\nrun the generated tests
|
||||
"Producer\nBuild"->"Producer": the tests passed
|
||||
"Producer"->"Repo\nwith\ncontracts": merge the pull request
|
||||
"Repo\nwith\ncontracts"->"CI": build and upload the\ncontract definitions artifact
|
||||
"CI"->"Stub Storage": upload the\ncontract definitions
|
||||
"Producer"->"Producer": setup the SCC Plugin\nto work remotely
|
||||
"Producer"->"Producer": merge the code\nwith the implementation
|
||||
"Producer"->"CI": build and upload\nthe artifacts
|
||||
"CI"->"Producer\nBuild\non CI": generate tests,\nstubs\nand stub jar
|
||||
"Producer\nBuild\non CI"->"SCC\nPlugin": generate tests,\nstubs\nand stub jar
|
||||
"SCC\nPlugin"->"Stub Storage": fetch the contract definitions
|
||||
"Stub Storage"->"SCC\nPlugin": contract definitions found
|
||||
"SCC\nPlugin"->"SCC\nPlugin": generate tests
|
||||
"Producer\nBuild\non CI"->"CI": the build passed
|
||||
"Producer\nBuild\non CI"->"Stub Storage": upload the application JAR\nand the stubs jar
|
||||
----
|
||||
|
||||
[[flows-cdc-contracts-stubs-git]]
|
||||
== Consumer-driven Contracts with Contracts on the Producer Side, Pushed to Git
|
||||
|
||||
You can read the <<getting-started.adoc#getting-started-cdc, Step-by-step Guide to Consumer Driven Contracts (CDC) with contracts laying on the producer side>> to see the consumer driven contracts with contracts on the producer side flow.
|
||||
|
||||
The stub storage implementation is a git repository. We describe its setup in the
|
||||
<<flows-provider-git>> section.
|
||||
|
||||
You can read more about setting up a git repository for the consumer and producer sides in
|
||||
the <<howto.adoc#how-to-use-git-as-storage,How To section>> of the documentation.
|
||||
|
||||
[[flows-provider-non-spring]]
|
||||
== Provider Contract Testing with Stubs in Artifactory for a non-Spring Application
|
||||
|
||||
[[flows-provider-non-spring-flow]]
|
||||
=== The Flow
|
||||
|
||||
You can read <<getting-started.adoc#getting-started-first-application, Developing Your First Spring Cloud Contract-based Application>> to see the flow for provider contract testing with stubs in Nexus or Artifactory.
|
||||
|
||||
[[flows-provider-non-spring-consumer]]
|
||||
=== Setting up the Consumer
|
||||
|
||||
For the consumer side, you can use a JUnit rule. That way, you need not start a Spring context. The following listing shows such a rule (in JUnit4 and JUnit 5);
|
||||
|
||||
====
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.JUnit 4 Rule
|
||||
----
|
||||
@Rule
|
||||
public StubRunnerRule rule = new StubRunnerRule()
|
||||
.downloadStub("com.example","artifact-id", "0.0.1")
|
||||
.repoRoot("git://git@github.com:spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git")
|
||||
.stubsMode(StubRunnerProperties.StubsMode.REMOTE);
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.JUnit 5 Extension
|
||||
----
|
||||
@RegisterExtension
|
||||
public StubRunnerExtension stubRunnerExtension = new StubRunnerExtension()
|
||||
.downloadStub("com.example","artifact-id", "0.0.1")
|
||||
.repoRoot("git://git@github.com:spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git")
|
||||
.stubsMode(StubRunnerProperties.StubsMode.REMOTE);
|
||||
----
|
||||
====
|
||||
|
||||
[[flows-provider-non-spring-producer]]
|
||||
=== Setting up the Producer
|
||||
|
||||
By default, the Spring Cloud Contract Plugin uses Rest Assured's `MockMvc` setup for the
|
||||
generated tests. Since non-Spring applications do not use `MockMvc`, you can change the
|
||||
`testMode` to `EXPLICIT` to send a real request to an application bound at a specific port.
|
||||
|
||||
In this example, we use a framework called https://javalin.io[Javalin] to start a
|
||||
non-Spring HTTP server.
|
||||
|
||||
Assume that we have the following application:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
----
|
||||
package com.example.demo;
|
||||
|
||||
import io.javalin.Javalin;
|
||||
|
||||
public class DemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new DemoApplication().run(7000);
|
||||
}
|
||||
|
||||
public Javalin start(int port) {
|
||||
return Javalin.create().start(port);
|
||||
}
|
||||
|
||||
public Javalin registerGet(Javalin app) {
|
||||
return app.get("/", ctx -> ctx.result("Hello World"));
|
||||
}
|
||||
|
||||
public Javalin run(int port) {
|
||||
return registerGet(start(port));
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Given that application, we can set up the plugin to use the `EXPLICIT` mode (that is, to
|
||||
send out requests to a real port), as follows:
|
||||
|
||||
====
|
||||
[source,xml,indent=0,role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<plugin>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
|
||||
<version>${spring-cloud-contract.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<baseClassForTests>com.example.demo.BaseClass</baseClassForTests>
|
||||
<!-- This will setup the EXPLICIT mode for the tests -->
|
||||
<testMode>EXPLICIT</testMode>
|
||||
</configuration>
|
||||
</plugin>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
contracts {
|
||||
// This will setup the EXPLICIT mode for the tests
|
||||
testMode = "EXPLICIT"
|
||||
baseClassForTests = "com.example.demo.BaseClass"
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The base class might resemble the following:
|
||||
|
||||
====
|
||||
[source,java,indent=0]
|
||||
----
|
||||
import io.javalin.Javalin;
|
||||
import io.restassured.RestAssured;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.springframework.cloud.test.TestSocketUtils;
|
||||
|
||||
public class BaseClass {
|
||||
|
||||
Javalin app;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
// pick a random port
|
||||
int port = TestSocketUtils.findAvailableTcpPort();
|
||||
// start the application at a random port
|
||||
this.app = start(port);
|
||||
// tell Rest Assured where the started application is
|
||||
RestAssured.baseURI = "http://localhost:" + port;
|
||||
}
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
// stop the server after each test
|
||||
this.app.stop();
|
||||
}
|
||||
|
||||
private Javalin start(int port) {
|
||||
// reuse the production logic to start a server
|
||||
return new DemoApplication().run(port);
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
With such a setup:
|
||||
|
||||
* We have set up the Spring Cloud Contract plugin to use the `EXPLICIT` mode to send real
|
||||
requests instead of mocked ones.
|
||||
* We have defined a base class that:
|
||||
** Starts the HTTP server on a random port for each test.
|
||||
** Sets Rest Assured to send requests to that port.
|
||||
** Closes the HTTP server after each test.
|
||||
|
||||
[[flows-provider-non-jvm]]
|
||||
== Provider Contract Testing with Stubs in Artifactory in a Non-JVM World
|
||||
|
||||
In this flow, we assume that:
|
||||
|
||||
* The API Producer and API Consumer are non-JVM applications.
|
||||
* The contract definitions are written in YAML.
|
||||
* The Stub Storage is Artifactory or Nexus.
|
||||
* Spring Cloud Contract Docker (SCC Docker) and Spring Cloud Contract Stub Runner Docker
|
||||
(SCC Stub Runner Docker) images are used.
|
||||
|
||||
You can read more about how to use Spring Cloud Contract with Docker link:docker-project.html[here].
|
||||
|
||||
https://spring.io/blog/2018/02/13/spring-cloud-contract-in-a-polyglot-world[Here], you can
|
||||
read a blog post about how to use Spring Cloud Contract in a polyglot world.
|
||||
|
||||
https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs/[Here], you can find
|
||||
a sample of a NodeJS application that uses Spring Cloud Contract both as a producer and a
|
||||
consumer.
|
||||
|
||||
[[flows-provider-non-jvm-producer]]
|
||||
=== Producer Flow
|
||||
|
||||
At a high level, the producer:
|
||||
|
||||
. Writes contract definitions (for example, in YAML).
|
||||
. Sets up the build tool to:
|
||||
.. Start the application with mocked services on a given port.
|
||||
+
|
||||
If mocking is not possible, you can set up the infrastructure and define tests in a stateful way.
|
||||
.. Run the Spring Cloud Contract Docker image and pass the port of a running application as an environment variable.
|
||||
|
||||
The SCC Docker image:
|
||||
* Generates the tests from the attached volume.
|
||||
* Runs the tests against the running application.
|
||||
|
||||
Upon test completion, stubs get uploaded to a stub storage site (such as Artifactory or Git).
|
||||
|
||||
The following UML diagram shows the producer flow:
|
||||
|
||||
[plantuml, flows-provider-non-jvm-producer, png]
|
||||
----
|
||||
"API Producer"->"API Producer": write contract definitions
|
||||
"API Producer"->"API Producer": (preferable) prepare a way\nto run the app\nwith mocked services
|
||||
"API Producer"->"API Producer\nbuild": run the build
|
||||
"API Producer\nbuild"->"API Producer\nrunning app": run the app\non port X\nwith mocked services
|
||||
"API Producer\nbuild"->"SCC Docker": attach contract definitions\nas a volume
|
||||
"API Producer\nbuild"->"SCC Docker": set environment variables\ne.g. app running on port X
|
||||
"API Producer\nbuild"->"SCC Docker": run the contract tests
|
||||
"SCC Docker"->"SCC Docker\nimage": run the contract tests
|
||||
"SCC Docker\nimage"->"SCC Docker\nimage": pick the contract definitions\nfrom volume
|
||||
"SCC Docker\nimage"->"SCC Docker\nimage": generate contract tests
|
||||
"SCC Docker\nimage"->"SCC Docker\nimage": run the tests\nagainst app running\non port X
|
||||
"SCC Docker\nimage"->"SCC Docker\nimage": the tests are passing!
|
||||
"SCC Docker\nimage"->"Stub Storage": upload the stubs
|
||||
"SCC Docker\nimage"->"SCC Docker": build successful
|
||||
"SCC Docker"->"API Producer\nbuild": build successful
|
||||
"API Producer\nbuild"->"API Producer": build successful
|
||||
----
|
||||
|
||||
[[flows-provider-non-jvm-consumer]]
|
||||
=== Consumer Flow
|
||||
|
||||
At a high level, the consumer:
|
||||
|
||||
. Sets up the build tool to:
|
||||
* Start the Spring Cloud Contract Stub Runner Docker image and start the stubs.
|
||||
+
|
||||
The environment variables configure:
|
||||
* The stubs to fetch.
|
||||
* The location of the repositories.
|
||||
+
|
||||
Note that:
|
||||
* To use the local storage, you can also attach it as a volume.
|
||||
* The ports at which the stubs are running need to be exposed.
|
||||
. Run the application tests against the running stubs.
|
||||
|
||||
The following UML diagram shows the consumer flow:
|
||||
|
||||
[plantuml, flows-provider-non-jvm-consumer, png]
|
||||
----
|
||||
"API Consumer"->"API Consumer\nbuild": run the build
|
||||
"API Consumer\nbuild"->"SCC\nStub Runner\nDocker": set environment variables\ne.g. stub X running on port Y
|
||||
"SCC\nStub Runner\nDocker"->"SCC\nStub Runner\nDocker\nimage": fetch and run\nthe stubs
|
||||
"SCC\nStub Runner\nDocker\nimage"->"Stub Storage": fetch the stubs of X
|
||||
"Stub Storage"->"SCC\nStub Runner\nDocker\nimage": stubs found
|
||||
"SCC\nStub Runner\nDocker\nimage"->"X Stub": run the stub of X
|
||||
"X Stub"->"SCC\nStub Runner\nDocker\nimage": stub is running\non port Y
|
||||
"SCC\nStub Runner\nDocker\nimage"->"SCC\nStub Runner\nDocker": stubs running and\nready for tests
|
||||
"API Consumer\nbuild"->"API Consumer\nbuild": run tests against X stub
|
||||
"API Consumer\nbuild"->"X Stub": send a request
|
||||
"X Stub"->"API Consumer\nbuild": response received
|
||||
"API Consumer\nbuild"->"API Consumer": build successful
|
||||
----
|
||||
|
||||
[[flows-provider-rest-docs]]
|
||||
== Provider Contract Testing with REST Docs and Stubs in Nexus or Artifactory
|
||||
|
||||
In this flow, we do not use a Spring Cloud Contract plugin to generate tests and stubs. We write https://spring.io/projects/spring-restdocs[Spring RESTDocs], and, from them, we automatically generate stubs. Finally, we set up our builds to package the stubs and upload them to the stub storage site -- in our case, Nexus or Artifactory.
|
||||
|
||||
[[flows-provider-rest-docs-producer]]
|
||||
=== Producer Flow
|
||||
|
||||
As a producer, we:
|
||||
|
||||
. Write RESTDocs tests of our API.
|
||||
. Add Spring Cloud Contract Stub Runner starter to our build (`spring-cloud-starter-contract-stub-runner`), as follows:
|
||||
+
|
||||
====
|
||||
[source,xml,indent=0,role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<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>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
dependencies {
|
||||
testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-stub-runner'
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
. We set up the build tool to package our stubs, as follows:
|
||||
+
|
||||
====
|
||||
[source,xml,indent=0,role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<!-- pom.xml -->
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>stub</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<inherited>false</inherited>
|
||||
<configuration>
|
||||
<attach>true</attach>
|
||||
<descriptors>
|
||||
${basedir}/src/assembly/stub.xml
|
||||
</descriptors>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<!-- src/assembly/stub.xml -->
|
||||
<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>stubs</id>
|
||||
<formats>
|
||||
<format>jar</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/generated-snippets/stubs</directory>
|
||||
<outputDirectory>META-INF/${project.groupId}/${project.artifactId}/${project.version}/mappings</outputDirectory>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
task stubsJar(type: Jar) {
|
||||
classifier = "stubs"
|
||||
into("META-INF/${project.group}/${project.name}/${project.version}/mappings") {
|
||||
include('**/*.*')
|
||||
from("${project.buildDir}/generated-snippets/stubs")
|
||||
}
|
||||
}
|
||||
// we need the tests to pass to build the stub jar
|
||||
stubsJar.dependsOn(test)
|
||||
bootJar.dependsOn(stubsJar)
|
||||
----
|
||||
====
|
||||
|
||||
Now, when we run the tests, stubs are automatically published and packaged.
|
||||
|
||||
The following UML diagram shows the producer flow:
|
||||
|
||||
[plantuml, flows-provider-rest-docs-producer, png]
|
||||
----
|
||||
"API Producer"->"API Producer": write RESTDocs tests
|
||||
"API Producer"->"API Producer": add the stub runner\nstarter dependency
|
||||
"API Producer"->"API Producer": setup the build tool to package\nthe generated stubs
|
||||
"API Producer"->"API Producer\nbuild": run the build
|
||||
"API Producer\nbuild"->"RESTDocs": generate HTTP snippets
|
||||
"RESTDocs"->"Spring Cloud\nContract": generate HTTP stubs
|
||||
"RESTDocs"->"Spring Cloud\nContract": (optional) generate\ncontract DSLs
|
||||
"Spring Cloud\nContract"->"RESTDocs": files generated
|
||||
"RESTDocs"->"API Producer\nbuild": snippets generated
|
||||
"API Producer\nbuild"->"API Producer\nbuild": tests passed
|
||||
"API Producer\nbuild"->"API Producer\nbuild": generate stubs jar
|
||||
"API Producer\nbuild"->"Stub Storage": upload JAR with the application
|
||||
"API Producer\nbuild"->"Stub Storage": upload JAR with the stubs
|
||||
"Stub Storage"->"API Producer\nbuild": JARs uploaded
|
||||
"API Producer\nbuild"->"API Producer": build successful
|
||||
----
|
||||
|
||||
[[flows-provider-rest-docs-consumer]]
|
||||
=== Consumer Flow
|
||||
|
||||
Since the consumer flow is not affected by the tool used to generate the stubs, you can read <<getting-started.adoc#getting-started-first-application-consumer, Developing Your First Spring Cloud Contract-based Application>> to see the flow for consumer side of the provider contract testing with stubs in Nexus or Artifactory.
|
||||
|
||||
[[using-whats-next]]
|
||||
== What to Read Next
|
||||
|
||||
You should now understand how you can use {project-full-name} and some best practices that you
|
||||
should follow. You can now go on to learn about specific
|
||||
<<project-features#project-features, {project-full-name} features>>, or you could
|
||||
skip ahead and read about the link:advanced.html[advanced features of {project-full-name}].
|
||||
@@ -1,13 +0,0 @@
|
||||
[[yml-schema]]
|
||||
== YML Schema
|
||||
include::_attributes.adoc[]
|
||||
|
||||
Below you can find a JSON schema definition of a YAML contract.
|
||||
|
||||
====
|
||||
[source,json,indent=0]
|
||||
----
|
||||
// TODO: reenable
|
||||
//include::{project-root}/docs/target/contract_schema.json[indent=0]
|
||||
----
|
||||
====
|
||||
Reference in New Issue
Block a user