Updated antora docs
This commit is contained in:
@@ -7,7 +7,7 @@ Edit the files in the src/main/asciidoc/ directory instead.
|
||||
|
||||
[[spring-cloud-contract]]
|
||||
= Spring Cloud Contract
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
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
|
||||
@@ -17,12 +17,12 @@ producers and consumers -- for both HTTP and message-based interactions.
|
||||
|
||||
[[project-page]]
|
||||
= Project page
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
You can read more about Spring Cloud Contract by going to https://spring.io/projects/spring-cloud-contract[the project page]
|
||||
|
||||
[[contributing]]
|
||||
= Contributing
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
Unresolved directive in <stdin> - include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/docs/src/main/asciidoc/contributing.adoc[]
|
||||
|
||||
@@ -23,16 +23,17 @@ asciidoc:
|
||||
hide-uri-scheme: '@'
|
||||
tabs-sync-option: '@'
|
||||
chomp: 'all'
|
||||
plantuml-server-url: http://www.plantuml.com/plantuml
|
||||
kroki-fetch-diagram: true
|
||||
extensions:
|
||||
- '@asciidoctor/tabs'
|
||||
- '@springio/asciidoctor-extensions' #TODO: Add plantuml rendering
|
||||
- 'asciidoctor-kroki'
|
||||
sourcemap: true
|
||||
urls:
|
||||
latest_version_segment: ''
|
||||
runtime:
|
||||
log:
|
||||
failure_level: error # at least until we figure out what's wrong in contract files
|
||||
failure_level: warn
|
||||
format: pretty
|
||||
ui:
|
||||
bundle:
|
||||
|
||||
@@ -7,22 +7,18 @@
|
||||
** xref:getting-started/cdc.adoc[]
|
||||
** xref:getting-started/whats-next.adoc[]
|
||||
* xref:using.adoc[]
|
||||
** xref:using/provider-contract-testing-with-stubs.adoc[]
|
||||
** xref:using/provider-contract-testing-with-stubs-in-git.adoc[]
|
||||
** xref:using/cdc-producer-side.adoc[]
|
||||
** xref:using/cdc-external-repo.adoc[]
|
||||
** xref:using/cdc-git.adoc[]
|
||||
** xref:using/provider-contract-testing-non-spring.adoc[]
|
||||
** xref:using/provider-contract-testing-non-jvm.adoc[]
|
||||
** xref:using/provider-contract-testing-rest-docs.adoc[]
|
||||
* xref:project-features.adoc[]
|
||||
*** xref:project-features-contract/groovy.adoc[]
|
||||
*** xref:project-features-contract/java.adoc[]
|
||||
*** xref:project-features-contract/kotlin.adoc[]
|
||||
*** xref:project-features-contract/yml.adoc[]
|
||||
*** xref:project-features-contract/limitations.adoc[]
|
||||
*** xref:project-features-contract/common-top-elements.adoc[]
|
||||
** xref:project-features-contract.adoc[]
|
||||
*** xref:project-features-contract/dsl-http-top-level-elements.adoc[]
|
||||
*** xref:project-features-contract/dsl-request.adoc[]
|
||||
*** xref:project-features-contract/dsl-response.adoc[]
|
||||
*** xref:project-features-contract/common-top-elements.adoc[]
|
||||
*** xref:project-features-contract/dsl-dynamic-properties.adoc[]
|
||||
*** xref:project-features-contract/dsl-async.adoc[]
|
||||
*** xref:project-features-contract/dsl-xml.adoc[]
|
||||
*** xref:project-features-contract/dsl-multiple.adoc[]
|
||||
*** xref:project-features-contract/stateful-contracts.adoc[]
|
||||
** xref:project-features-integrations.adoc[]
|
||||
*** xref:project-features-flows/jax-rs.adoc[]
|
||||
*** xref:project-features-flows/feature-webflux.adoc[]
|
||||
@@ -69,6 +65,9 @@
|
||||
** xref:howto/how-to-use-the-failonnostubs-feature.adoc[]
|
||||
** xref:howto/how-to-mark-contract-in-progress.adoc[]
|
||||
* xref:advanced.adoc[]
|
||||
** xref:customization/dsl-customization.adoc[]
|
||||
** xref:customization/wiremock-customization.adoc[]
|
||||
** xref:customization/pluggable-architecture.adoc[]
|
||||
* xref:appendix.adoc[]
|
||||
** xref:building.adoc[]
|
||||
** xref:configprops.adoc[]
|
||||
|
||||
@@ -3,376 +3,4 @@
|
||||
|
||||
include::partial$_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.
|
||||
|
||||
{samples_url}/common/src/main/java/com/example/PatternUtils.java[PatternUtils] contains functions used by both the consumer and the producer.
|
||||
|
||||
{samples_url}/common/src/main/java/com/example/ConsumerUtils.java[ConsumerUtils] contains functions used by the consumer.
|
||||
|
||||
{samples_url}/common/src/main/java/com/example/ProducerUtils.java[ProducerUtils] contains functions used by the producer.
|
||||
|
||||
[[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 {samples_url}/producer/[example] show how to test the dependency.
|
||||
|
||||
[[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.
|
||||
|
||||
[[customization-referencing]]
|
||||
=== Referencing Classes in DSLs
|
||||
|
||||
You can now reference your classes in your DSL, as the {samples_url}/producer/src/test/resources/contracts/beer/rest/shouldGrantABeerIfOldEnough.groovy[following example shows].
|
||||
|
||||
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_root_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_root_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`
|
||||
|====
|
||||
In this section, we describe how to customize various parts of Spring Cloud Contract.
|
||||
@@ -2,7 +2,7 @@
|
||||
[appendix]
|
||||
[[common-application-properties]]
|
||||
= Common application properties
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
|
||||
54
docs/modules/ROOT/pages/customization/dsl-customization.adoc
Normal file
54
docs/modules/ROOT/pages/customization/dsl-customization.adoc
Normal file
@@ -0,0 +1,54 @@
|
||||
[[customization-customization]]
|
||||
= DSL Customization
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
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.
|
||||
|
||||
{samples_url}/common/src/main/java/com/example/PatternUtils.java[PatternUtils] contains functions used by both the consumer and the producer.
|
||||
|
||||
{samples_url}/common/src/main/java/com/example/ConsumerUtils.java[ConsumerUtils] contains functions used by the consumer.
|
||||
|
||||
{samples_url}/common/src/main/java/com/example/ProducerUtils.java[ProducerUtils] contains functions used by the producer.
|
||||
|
||||
[[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 {samples_url}/producer/[example] show how to test the dependency.
|
||||
|
||||
[[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.
|
||||
|
||||
[[customization-referencing]]
|
||||
== Referencing Classes in DSLs
|
||||
|
||||
You can now reference your classes in your DSL, as the {samples_url}/producer/src/test/resources/contracts/beer/rest/shouldGrantABeerIfOldEnough.groovy[following example shows].
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,227 @@
|
||||
[[customization-pluggable-architecture]]
|
||||
= Using the Pluggable Architecture
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
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_root_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`
|
||||
|===
|
||||
@@ -0,0 +1,94 @@
|
||||
[[customization-wiremock]]
|
||||
= WireMock Customization
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
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_root_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.
|
||||
@@ -184,7 +184,7 @@ The contract needs to call a `triggerMessage(...)` method. That method is alread
|
||||
======
|
||||
Groovy::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="primary"]
|
||||
----
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
|
||||
@@ -220,7 +220,7 @@ Contract.make {
|
||||
|
||||
YAML::
|
||||
+
|
||||
[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,yml,indent=0,subs="verbatim",role="secondary"]
|
||||
----
|
||||
description: 'Send a pong message in response to a ping message'
|
||||
label: 'ping_pong'
|
||||
@@ -259,7 +259,7 @@ 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"]
|
||||
[source,python,indent=0,subs="verbatim"]
|
||||
.Python
|
||||
----
|
||||
#!/usr/bin/env python
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[getting-started]]
|
||||
= Getting Started
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ following section to your build:
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,xml,indent=0,subs="verbatim",role="primary"]
|
||||
----
|
||||
include::{samples_path}/standalone/dsl/http-server/pom.xml[tags=repos,indent=0]
|
||||
----
|
||||
@@ -47,7 +47,7 @@ include::{samples_path}/standalone/dsl/http-server/pom.xml[tags=repos,indent=0]
|
||||
////
|
||||
|
||||
////
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
include::{samples_path}/standalone/dsl/http-server/build.gradle[tags=deps_repos,indent=0]
|
||||
|
||||
@@ -22,7 +22,7 @@ To add a Gradle plugin with dependencies, you can use code similar to the follow
|
||||
======
|
||||
Plugin DSL GA versions::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="primary"]
|
||||
----
|
||||
// build.gradle
|
||||
plugins {
|
||||
@@ -48,7 +48,7 @@ dependencies {
|
||||
|
||||
Plugin DSL non GA versions::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
----
|
||||
// settings.gradle
|
||||
pluginManagement {
|
||||
@@ -90,7 +90,7 @@ dependencies {
|
||||
|
||||
Legacy Plugin Application::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
----
|
||||
// build.gradle
|
||||
buildscript {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[howto]]
|
||||
= "`How-to`" Guides
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
|
||||
@@ -11,14 +11,14 @@ To do so, include the following dependencies (if you have not already done so):
|
||||
======
|
||||
maven::
|
||||
+
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,xml,indent=0,subs="verbatim",role="primary"]
|
||||
----
|
||||
include::{standalone_restdocs_path}/http-server/pom.xml[tags=dependencies,indent=0]
|
||||
----
|
||||
|
||||
gradle::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
----
|
||||
include::{standalone_restdocs_path}/http-server/build.gradle[tags=dependencies,indent=0]
|
||||
----
|
||||
@@ -31,14 +31,14 @@ Next, you need to make some changes to your base class. The following examples u
|
||||
======
|
||||
WebAppContext::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||
----
|
||||
include::{standalone_restdocs_path}/http-server/src/test/java/com/example/fraud/FraudBaseWithWebAppSetup.java[tags=base_class,indent=0]
|
||||
----
|
||||
|
||||
Standalone::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
----
|
||||
include::{standalone_restdocs_path}/http-server/src/test/java/com/example/fraud/FraudBaseWithStandaloneSetup.java[tags=base_class,indent=0]
|
||||
----
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[how-to-debug-wiremock]]
|
||||
= How Can I Debug the Mapping, Request, or Response Being Sent by WireMock?
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[how-to-debug]]
|
||||
= How Can I Debug the Request/Response Being Sent by the Generated Tests Client?
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[how-to-generate-stubs-at-runtime]]
|
||||
= How Can I Generate Stubs at Runtime
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[how-to-mark-contract-in-progress]]
|
||||
= How Can I Mark that a Contract Is in Progress
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[how-to-not-write-contracts-in-groovy]]
|
||||
= How Can I Write Contracts in a Language Other than Groovy?
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
You can write a contract in YAML. See xref:../project-features-contract.adoc[this section] for more information.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[how-to-reference-text-from-file]]
|
||||
= How Can I Reference Text from File?
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[how-to-see-registered-stubs]]
|
||||
= How Can I See What Got Registered in the HTTP Server Stub?
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[how-to-use-stubs-from-a-location]]
|
||||
= How Can I Use Stubs from a Location
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[how-to-use-the-failonnostubs-feature]]
|
||||
= How Can I Make The Build Pass if There Are No Contracts or Stubs
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[why-spring-cloud-contract]]
|
||||
= Why use Spring Cloud Contract?
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[spring-cloud-contract-reference-documentation]]
|
||||
= Spring Cloud Contract Reference Documentation
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
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
|
||||
|
||||
Spring Cloud Contract moves TDD to the level of software architecture. It lets you perform consumer-driven and producer-driven contract testing.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[legal]
|
||||
[[legal]]
|
||||
= Legal
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
{project-version}
|
||||
|
||||
|
||||
@@ -15,25 +15,25 @@ TIP: Spring Cloud Contract supports defining multiple contracts in a single file
|
||||
The following example shows a contract definition:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="primary"]
|
||||
.Groovy
|
||||
----
|
||||
include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy[tags=dsl_example,indent=0]
|
||||
----
|
||||
|
||||
[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,yml,indent=0,subs="verbatim",role="secondary"]
|
||||
.YAML
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract_rest.yml[indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_rest.java[tags=class,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/kotlin/contract_rest.kts[tags=class,indent=0]
|
||||
@@ -49,3 +49,16 @@ mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:convert
|
||||
----
|
||||
====
|
||||
|
||||
include::project-features-contract/_groovy.adoc[]
|
||||
|
||||
include::project-features-contract/_java.adoc[]
|
||||
|
||||
include::project-features-contract/_kotlin.adoc[]
|
||||
|
||||
include::project-features-contract/_yml.adoc[]
|
||||
|
||||
include::project-features-contract/_limitations.adoc[]
|
||||
|
||||
include::project-features-contract/_dsl-multiple.adoc[]
|
||||
|
||||
include::project-features-contract/_stateful-contracts.adoc[]
|
||||
@@ -1,5 +1,5 @@
|
||||
[[contract-dsl-async]]
|
||||
= Asynchronous Support
|
||||
== Asynchronous Support
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
@@ -8,7 +8,7 @@ returning `Callable`, `DeferredResult`, and so on), then, inside your contract,
|
||||
provide an `async()` method in the `response` section. The following code shows an example:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="primary"]
|
||||
.Groovy
|
||||
----
|
||||
org.springframework.cloud.contract.spec.Contract.make {
|
||||
@@ -24,14 +24,14 @@ org.springframework.cloud.contract.spec.Contract.make {
|
||||
}
|
||||
----
|
||||
|
||||
[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,yml,indent=0,subs="verbatim",role="secondary"]
|
||||
.YAML
|
||||
----
|
||||
response:
|
||||
async: true
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
class contract implements Supplier<Collection<Contract>> {
|
||||
@@ -52,7 +52,7 @@ class contract implements Supplier<Collection<Contract>> {
|
||||
}
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract
|
||||
@@ -73,7 +73,7 @@ You can also use the `fixedDelayMilliseconds` method or property to add delay to
|
||||
The following example shows how to do so:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="primary"]
|
||||
.Groovy
|
||||
----
|
||||
org.springframework.cloud.contract.spec.Contract.make {
|
||||
@@ -89,14 +89,14 @@ org.springframework.cloud.contract.spec.Contract.make {
|
||||
}
|
||||
----
|
||||
|
||||
[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,yml,indent=0,subs="verbatim",role="secondary"]
|
||||
.YAML
|
||||
----
|
||||
response:
|
||||
fixedDelayMilliseconds: 1000
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
class contract implements Supplier<Collection<Contract>> {
|
||||
@@ -117,7 +117,7 @@ class contract implements Supplier<Collection<Contract>> {
|
||||
}
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract
|
||||
@@ -1,5 +1,5 @@
|
||||
[[contract-dsl-http-top-level-elements]]
|
||||
= HTTP Top-Level Elements
|
||||
== HTTP Top-Level Elements
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
@@ -12,13 +12,13 @@ You can call the following methods in the top-level closure of a contract defini
|
||||
The following example shows how to define an HTTP request contract:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="primary"]
|
||||
.Groovy
|
||||
----
|
||||
include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=http_dsl,indent=0]
|
||||
----
|
||||
|
||||
[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,yml,indent=0,subs="verbatim",role="secondary"]
|
||||
.YAML
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=priority,indent=0]
|
||||
@@ -28,13 +28,13 @@ include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=response,
|
||||
...
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=http_dsl,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=http_dsl,indent=0]
|
||||
@@ -1,5 +1,5 @@
|
||||
[[contract-dsl-multiple]]
|
||||
= Multiple Contracts in One File
|
||||
== Multiple Contracts in One File
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
@@ -19,7 +19,7 @@ include::{plugins_path}/spring-cloud-contract-maven-plugin/src/test/projects/mul
|
||||
include::{verifier_root_path}/src/test/resources/yml/multiple_contracts.yml[indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
class contract implements Supplier<Collection<Contract>> {
|
||||
@@ -41,7 +41,7 @@ class contract implements Supplier<Collection<Contract>> {
|
||||
}
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract
|
||||
@@ -1,5 +1,5 @@
|
||||
[[contract-dsl-request]]
|
||||
= HTTP Request
|
||||
== HTTP Request
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
@@ -21,13 +21,13 @@ include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=request_obligatory,indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=request,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=request,indent=0]
|
||||
@@ -52,13 +52,13 @@ include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract_rest_with_path.yml[tags=url_path,indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=url,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=url,indent=0]
|
||||
@@ -68,13 +68,13 @@ include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.k
|
||||
`request` may contain query parameters, as the following example (which uses `urlPath`) shows:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="primary"]
|
||||
.Groovy
|
||||
----
|
||||
include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=urlpath,indent=0]
|
||||
----
|
||||
|
||||
[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,yml,indent=0,subs="verbatim",role="secondary"]
|
||||
.YAML
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
|
||||
@@ -82,13 +82,13 @@ include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=request,i
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=query_params,indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=urlpath,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=urlpath,indent=0]
|
||||
@@ -98,13 +98,13 @@ include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.k
|
||||
`request` can contain additional request headers, as the following example shows:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="primary"]
|
||||
.Groovy
|
||||
----
|
||||
include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=headers,indent=0]
|
||||
----
|
||||
|
||||
[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,yml,indent=0,subs="verbatim",role="secondary"]
|
||||
.YAML
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
|
||||
@@ -112,13 +112,13 @@ include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=request,i
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=headers,indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=headers,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=headers,indent=0]
|
||||
@@ -128,13 +128,13 @@ include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.k
|
||||
`request` may contain additional request cookies, as the following example shows:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="primary"]
|
||||
.Groovy
|
||||
----
|
||||
include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=cookies,indent=0]
|
||||
----
|
||||
|
||||
[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,yml,indent=0,subs="verbatim",role="secondary"]
|
||||
.YAML
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
|
||||
@@ -142,13 +142,13 @@ include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=request,i
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=cookies,indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=cookies,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=cookies,indent=0]
|
||||
@@ -158,13 +158,13 @@ include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.k
|
||||
`request` may contain a request body, as the following example shows:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="primary"]
|
||||
.Groovy
|
||||
----
|
||||
include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=body,indent=0]
|
||||
----
|
||||
|
||||
[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,yml,indent=0,subs="verbatim",role="secondary"]
|
||||
.YAML
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
|
||||
@@ -172,13 +172,13 @@ include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=request,i
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=body,indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=body,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=body,indent=0]
|
||||
@@ -201,13 +201,13 @@ include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract_multipart.yml[indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_multipart.java[tags=class,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/kotlin/multipart.kts[tags=class,indent=0]
|
||||
@@ -246,7 +246,7 @@ Check this https://github.com/spring-cloud/spring-cloud-contract/issues/1886[iss
|
||||
From the contract in the preceding example, the generated test and stub look as follows:
|
||||
|
||||
====
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||
.Test
|
||||
----
|
||||
// given:
|
||||
@@ -264,7 +264,7 @@ From the contract in the preceding example, the generated test and stub look as
|
||||
assertThat(response.statusCode()).isEqualTo(200);
|
||||
----
|
||||
|
||||
[source,json,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,json,indent=0,subs="verbatim",role="secondary"]
|
||||
.Stub
|
||||
----
|
||||
include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockGroovyDslSpec.groovy[tags=multipartwiremock,indent=0]
|
||||
@@ -1,5 +1,5 @@
|
||||
[[contract-dsl-response]]
|
||||
= HTTP Response
|
||||
== HTTP Response
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
@@ -7,13 +7,13 @@ The response must contain an HTTP status code and may contain other information.
|
||||
following code shows an example:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="primary"]
|
||||
.Groovy
|
||||
----
|
||||
include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=response,indent=0]
|
||||
----
|
||||
|
||||
[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,yml,indent=0,subs="verbatim",role="secondary"]
|
||||
.YAML
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=response,indent=0]
|
||||
@@ -21,13 +21,13 @@ include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=response,
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=response_obligatory,indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=response,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=response,indent=0]
|
||||
@@ -35,7 +35,7 @@ include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.k
|
||||
====
|
||||
|
||||
Besides status, the response may contain headers, cookies, and a body, which are
|
||||
specified the same way as in the request (see xref:project-features-contract/dsl-request.adoc[HTTP Request]).
|
||||
specified the same way as in the request (see xref:project-features-contract/http.adoc#contract-dsl-request[HTTP Request]).
|
||||
|
||||
TIP: In the Groovy DSL, you can reference the `org.springframework.cloud.contract.spec.internal.HttpStatus`
|
||||
methods to provide a meaningful status instead of a digit. For example, you can call
|
||||
@@ -1,5 +1,5 @@
|
||||
[[contract-dsl-xml]]
|
||||
= XML Support for HTTP
|
||||
== XML Support for HTTP
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
@@ -13,25 +13,25 @@ and the appropriate `MatchingType` as the second argument. All the body matchers
|
||||
The following example shows a Groovy DSL contract with XML in the response body:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="primary"]
|
||||
.Groovy
|
||||
----
|
||||
include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/XmlMethodBodyBuilderSpec.groovy[tags=xmlgroovy]
|
||||
----
|
||||
|
||||
[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,yml,indent=0,subs="verbatim",role="secondary"]
|
||||
.YAML
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract_rest_xml.yml[indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_xml.java[tags=class,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/kotlin/contract_xml.kts[tags=class,indent=0]
|
||||
@@ -72,7 +72,7 @@ public void validate_xmlMatches() throws Exception {
|
||||
====
|
||||
|
||||
[[xml-support-for-namespaces]]
|
||||
== XML Support for Namespaces
|
||||
=== XML Support for Namespaces
|
||||
Namespaced XML is supported. However, any XPath expresssions used to select namespaced content must be updated.
|
||||
|
||||
Consider the following explicitly namespaced XML document:
|
||||
@@ -104,7 +104,7 @@ WARNING: Beware, as the unqualified expressions (`/customer/email/text()` or `*/
|
||||
result in `""`. Even the child elements have to be referenced with the `local-name` syntax.
|
||||
|
||||
[[general-namespaced-node-expression-syntax]]
|
||||
=== General Namespaced Node Expression Syntax
|
||||
==== General Namespaced Node Expression Syntax
|
||||
- Node using qualified namespace:
|
||||
```
|
||||
/<node-name>
|
||||
@@ -1,6 +1,6 @@
|
||||
[[contract-groovy]]
|
||||
= Contract DSL in Groovy
|
||||
:page-section-summary-toc: 1
|
||||
== Contract DSL in Groovy
|
||||
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[[contract-java]]
|
||||
= Contract DSL in Java
|
||||
== Contract DSL in Java
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
@@ -10,7 +10,7 @@ You can also write the contract definitions under `src/test/java` (for example,
|
||||
The following example (in both Maven and Gradle) has the contract definitions under `src/test/java`:
|
||||
|
||||
====
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,xml,indent=0,subs="verbatim",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<plugin>
|
||||
@@ -24,7 +24,7 @@ The following example (in both Maven and Gradle) has the contract definitions un
|
||||
</plugin>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
contracts {
|
||||
@@ -1,5 +1,5 @@
|
||||
[[contract-kotlin]]
|
||||
= Contract DSL in Kotlin
|
||||
== Contract DSL in Kotlin
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
@@ -16,7 +16,7 @@ You need to explicitly pass the `spring-cloud-contract-spec-kotlin` dependency t
|
||||
The following example (in both Maven and Gradle) shows how to do so:
|
||||
|
||||
====
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,xml,indent=0,subs="verbatim",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<plugin>
|
||||
@@ -46,7 +46,7 @@ The following example (in both Maven and Gradle) shows how to do so:
|
||||
</dependencies>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
buildscript {
|
||||
@@ -1,6 +1,6 @@
|
||||
[[contract-limitations]]
|
||||
= Limitations
|
||||
:page-section-summary-toc: 1
|
||||
== Limitations
|
||||
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[[contract-stateful-contracts]]
|
||||
= Stateful Contracts
|
||||
== Stateful Contracts
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[contract-yml]]
|
||||
= Contract DSL in YAML
|
||||
:page-section-summary-toc: 1
|
||||
== Contract DSL in YAML
|
||||
|
||||
|
||||
To see a schema of a YAML contract, visit the xref:../yml-schema.adoc[YML Schema] page.
|
||||
|
||||
@@ -31,13 +31,13 @@ include::{contract_spec_tests_path}/src/test/groovy/org/springframework/cloud/co
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract_rest.yml[indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_rest_with_tags.java[tags=description,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{contract_kotlin_spec_path}/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt[tags=description,indent=0]
|
||||
@@ -72,13 +72,13 @@ include::{contract_spec_tests_path}/src/test/groovy/org/springframework/cloud/co
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=name,indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_rest_with_tags.java[tags=name,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{contract_kotlin_spec_path}/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt[tags=name,indent=0]
|
||||
@@ -105,13 +105,13 @@ include::{contract_spec_tests_path}/src/test/groovy/org/springframework/cloud/co
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=ignored,indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_rest_with_tags.java[tags=ignored,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{contract_kotlin_spec_path}/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt[tags=ignored,indent=0]
|
||||
@@ -141,13 +141,13 @@ include::{contract_spec_tests_path}/src/test/groovy/org/springframework/cloud/co
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract.yml[tags=in_progress,indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_rest_with_tags.java[tags=in_progress,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{contract_kotlin_spec_path}/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt[tags=in_progress,indent=0]
|
||||
@@ -188,13 +188,13 @@ include::{verifier_root_path}/src/test/resources/classpath/readFromFile.groovy[i
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract_from_file.yml[indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_rest_from_file.java[tags=class,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/kotlin/readFromFile.kts[tags=class,indent=0]
|
||||
@@ -204,13 +204,13 @@ include::{verifier_root_path}/src/test/resources/kotlin/readFromFile.kts[tags=cl
|
||||
Further assume that the JSON files are as follows:
|
||||
|
||||
====
|
||||
[source,json,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,json,indent=0,subs="verbatim",role="primary"]
|
||||
.request.json
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/classpath/request.json[indent=0]
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
.response.json
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/classpath/response.json[indent=0]
|
||||
@@ -239,13 +239,13 @@ include::{verifier_root_path}/src/test/resources/body_builder/worksWithPdf.groov
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract_pdf.yml[indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_rest_from_pdf.java[tags=class,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{contract_kotlin_spec_path}/src/test/resources/contracts/shouldWorkWithBinaryPayload.kts[tags=class,indent=0]
|
||||
@@ -276,13 +276,13 @@ include::{standalone_samples_path}/http-server/src/test/resources/contracts/frau
|
||||
include::{standalone_samples_path}/http-server/src/test/resources/contracts/yml/fraud/shouldReturnFraudStats.yml[tags=metadata,indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_rest_with_tags.java[tags=metadata,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.kotlin
|
||||
----
|
||||
include::{contract_kotlin_spec_path}/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt[tags=metadata,indent=0]
|
||||
|
||||
@@ -29,7 +29,7 @@ the Groovy map notation, with `$()`. The following example shows how to set dyna
|
||||
properties with the value method:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="primary"]
|
||||
.value
|
||||
----
|
||||
value(consumer(...), producer(...))
|
||||
@@ -38,7 +38,7 @@ value(stub(...), test(...))
|
||||
value(client(...), server(...))
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
.$
|
||||
----
|
||||
$(consumer(...), producer(...))
|
||||
@@ -76,13 +76,13 @@ The following example shows how to use regular expressions to write a request:
|
||||
include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=regex,indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=regex,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=regex,indent=0]
|
||||
@@ -134,7 +134,7 @@ The following example shows how you can reference those methods:
|
||||
include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=regex_creating_props,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=regex_creating_props,indent=0]
|
||||
@@ -173,13 +173,13 @@ The following example shows how to provide optional parameters:
|
||||
include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=optionals,indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=optionals,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=optionals,indent=0]
|
||||
@@ -223,13 +223,13 @@ following code shows an example of the contract portion of the test case:
|
||||
include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=method,indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=method,indent=0]
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=method,indent=0]
|
||||
@@ -340,7 +340,7 @@ include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract_reference_request.yml[indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Java
|
||||
----
|
||||
package contracts.beer.rest;
|
||||
@@ -380,7 +380,7 @@ class shouldReturnStatsForAUser implements Supplier<Contract> {
|
||||
}
|
||||
----
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
package contracts.beer.rest
|
||||
|
||||
15
docs/modules/ROOT/pages/project-features-contract/http.adoc
Normal file
15
docs/modules/ROOT/pages/project-features-contract/http.adoc
Normal file
@@ -0,0 +1,15 @@
|
||||
= HTTP Contracts
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
This page describes most important HTTP related parts of the contract.
|
||||
|
||||
include::_dsl-http-top-level-elements.adoc[]
|
||||
|
||||
include::_dsl-request.adoc[]
|
||||
|
||||
include::_dsl-response.adoc[]
|
||||
|
||||
include::_dsl-xml.adoc[]
|
||||
|
||||
include::_dsl-async.adoc[]
|
||||
@@ -13,7 +13,7 @@ side remains untouched. In order for the generated test to pass, you must use ex
|
||||
mode. The following example shows how to set the test mode to `EXPLICIT`:
|
||||
|
||||
====
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,xml,indent=0,subs="verbatim",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<plugin>
|
||||
@@ -27,7 +27,7 @@ mode. The following example shows how to set the test mode to `EXPLICIT`:
|
||||
</plugin>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
contracts {
|
||||
|
||||
@@ -7,7 +7,7 @@ You can also use WebFlux with the explicit mode in your generated tests
|
||||
to work with WebFlux. The following example shows how to configure using explicit mode:
|
||||
|
||||
====
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,xml,indent=0,subs="verbatim",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<plugin>
|
||||
@@ -21,7 +21,7 @@ to work with WebFlux. The following example shows how to configure using explici
|
||||
</plugin>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
contracts {
|
||||
|
||||
@@ -7,7 +7,7 @@ You can work with WebFlux by using WebTestClient. The following listing shows ho
|
||||
configure WebTestClient as the test mode:
|
||||
|
||||
====
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,xml,indent=0,subs="verbatim",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<plugin>
|
||||
@@ -21,7 +21,7 @@ configure WebTestClient as the test mode:
|
||||
</plugin>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
contracts {
|
||||
|
||||
@@ -6,7 +6,7 @@ include::partial$_attributes.adoc[]
|
||||
Since https://graphql.org/[GraphQL] is essentially HTTP you can write a contract for it by creating a standard HTTP contract with an additional `metadata` entry with key `verifier` and a mapping `tool=graphql`.
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="primary"]
|
||||
.Groovy
|
||||
----
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
@@ -50,7 +50,7 @@ Contract.make {
|
||||
}
|
||||
----
|
||||
|
||||
[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,yml,indent=0,subs="verbatim",role="secondary"]
|
||||
.YAML
|
||||
----
|
||||
---
|
||||
@@ -99,7 +99,7 @@ Adding the metadata section will change the way the default, WireMock stub is bu
|
||||
On the producer side your configuration can look as follows.
|
||||
|
||||
====
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,xml,indent=0,subs="verbatim",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<plugin>
|
||||
@@ -114,7 +114,7 @@ On the producer side your configuration can look as follows.
|
||||
</plugin>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
contracts {
|
||||
@@ -127,7 +127,7 @@ contracts {
|
||||
The base class would set up the application running on a random port.
|
||||
|
||||
====
|
||||
[source,java,indent=0,subs="verbatim,attributes"]
|
||||
[source,java,indent=0,subs="verbatim"]
|
||||
.Base Class
|
||||
----
|
||||
@SpringBootTest(classes = ProducerApplication.class,
|
||||
@@ -152,7 +152,7 @@ public abstract class BaseClass {
|
||||
Example of a consumer side test of the GraphQL API.
|
||||
|
||||
====
|
||||
[source,java,indent=0,subs="verbatim,attributes"]
|
||||
[source,java,indent=0,subs="verbatim"]
|
||||
.Consumer Side Test
|
||||
----
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
|
||||
|
||||
@@ -10,7 +10,7 @@ IMPORTANT: Spring Cloud Contract has an experimental support for basic use cases
|
||||
Let's look at the following contract.
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes"]
|
||||
[source,groovy,indent=0,subs="verbatim"]
|
||||
.Groovy contract
|
||||
----
|
||||
package contracts.beer.rest
|
||||
@@ -66,7 +66,7 @@ then:
|
||||
In order to leverage the HTTP/2 support you must set the `CUSTOM` test mode as follow.
|
||||
|
||||
====
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,xml,indent=0,subs="verbatim",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<plugin>
|
||||
@@ -81,7 +81,7 @@ In order to leverage the HTTP/2 support you must set the `CUSTOM` test mode as f
|
||||
</plugin>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
contracts {
|
||||
@@ -94,7 +94,7 @@ contracts {
|
||||
The base class would set up the application running on a random port. It will also set the `HttpVerifier` implementation to one that can use the HTTP/2 protocol. Spring Cloud Contract comes with the `OkHttpHttpVerifier` implementation.
|
||||
|
||||
====
|
||||
[source,java,indent=0,subs="verbatim,attributes"]
|
||||
[source,java,indent=0,subs="verbatim"]
|
||||
.Base Class
|
||||
----
|
||||
@SpringBootTest(classes = BeerRestBase.Config.class,
|
||||
@@ -137,7 +137,7 @@ public abstract class BeerRestBase {
|
||||
Example of GRPC consumer side test. Due to the unusual behaviour of the GRPC server side, the stub is unable to return the `grpc-status` header in the proper moment. This is why we need to manually set the return status.
|
||||
|
||||
====
|
||||
[source,java,indent=0,subs="verbatim,attributes"]
|
||||
[source,java,indent=0,subs="verbatim"]
|
||||
.Consumer Side Test
|
||||
----
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.NONE, classes = GrpcTests.TestConfiguration.class, properties = {
|
||||
|
||||
@@ -256,7 +256,7 @@ contract. The location of this file would be `index/dsl-contract.adoc`.
|
||||
|
||||
The method `SpringCloudContractRestDocs.dslContract()` takes an optional Map parameter that allows you to specify additional attributes in the template.
|
||||
|
||||
One of these attributes is the xref:project-features-contract/dsl-http-top-level-elements.adoc[priority] field that you may specify as follows:
|
||||
One of these attributes is the xref:project-features-contract/http.adoc#contract-dsl-http-top-level-elements[priority] field that you may specify as follows:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
|
||||
@@ -24,13 +24,13 @@ The output message can be triggered by calling a method (such as a `Scheduler` w
|
||||
started and when a message was sent), as shown in the following example:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",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"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
.YAML
|
||||
----
|
||||
include::{verifier_root_path}/src/test/resources/yml/contract_message_method.yml[indent=0]
|
||||
@@ -85,7 +85,7 @@ 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"]
|
||||
[source,xml,indent=0,subs="verbatim",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<dependency>
|
||||
@@ -97,7 +97,7 @@ If you want to use Spring Cloud Stream, remember to add a test dependency on
|
||||
</dependency>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
testImplementation(group: 'org.springframework.cloud', name: 'spring-cloud-stream', classifier: 'test-binder')
|
||||
@@ -150,13 +150,13 @@ it is resolved as a channel name. For Camel, that's a certain component (for exa
|
||||
Consider the following contract:
|
||||
|
||||
=====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="primary"]
|
||||
.Groovy
|
||||
----
|
||||
include::{verifier_root_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"]
|
||||
[source,yml,indent=0,subs="verbatim",role="secondary"]
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
@@ -167,13 +167,13 @@ include::{verifier_root_path}/src/test/resources/yml/contract_message_scenario1.
|
||||
For the preceding example, the following test would be created:
|
||||
|
||||
====
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||
.JUnit
|
||||
----
|
||||
include::{verifier_root_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"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
.Spock
|
||||
----
|
||||
include::{verifier_root_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=trigger_method_test]
|
||||
@@ -444,7 +444,7 @@ 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"]
|
||||
[source,xml,indent=0,subs="verbatim",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<dependency>
|
||||
@@ -454,7 +454,7 @@ If you want to use Spring Cloud Stream, remember to add a dependency on
|
||||
</dependency>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
testImplementation('org.springframework.cloud:spring-cloud-stream-test-binder')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[features-stub-runner]]
|
||||
= Spring Cloud Contract Stub Runner
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
One of the issues that you might encounter while using Spring Cloud Contract Verifier is
|
||||
passing the generated WireMock JSON stubs from the server side to the client side (or to
|
||||
|
||||
@@ -61,7 +61,7 @@ Consider the following example:
|
||||
You can add the dependencies to your classpath, as follows:
|
||||
|
||||
====
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,xml,indent=0,subs="verbatim",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<dependency>
|
||||
@@ -92,7 +92,7 @@ You can add the dependencies to your classpath, as follows:
|
||||
</dependency>
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
testCompile("com.example:beer-api-producer-restdocs:0.0.1-SNAPSHOT:stubs") {
|
||||
|
||||
@@ -6,7 +6,7 @@ include::partial$_attributes.adoc[]
|
||||
By default, Stub Runner will fail if no stubs are found. In order to change that behavior, set the `failOnNoStubs` property to `false` in the annotation or call the `withFailOnNoStubs(false)` method on a JUnit Rule or Extension. The following example shows how to do so:
|
||||
|
||||
====
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||
.Annotation
|
||||
----
|
||||
@AutoConfigureStubRunner(
|
||||
@@ -16,7 +16,7 @@ stubsMode = StubRunnerProperties.StubsMode.REMOTE,
|
||||
failOnNoStubs = false)
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.JUnit 4 Rule
|
||||
----
|
||||
@Rule
|
||||
@@ -27,7 +27,7 @@ stubsMode = StubRunnerProperties.StubsMode.REMOTE,
|
||||
.withFailOnNoStubs(false);
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.JUnit 5 Extension
|
||||
----
|
||||
@RegisterExtension
|
||||
|
||||
@@ -10,7 +10,7 @@ As a producer, when a contract is defined, you are required to make the generate
|
||||
As a consumer, you can toggle a switch to generate stubs at runtime. Stub Runner ignores all the existing stub mappings and generates new ones for all the contract definitions. Another option is to pass the `stubrunner.generate-stubs` system property. The following example shows such a setup:
|
||||
|
||||
====
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||
.Annotation
|
||||
----
|
||||
@AutoConfigureStubRunner(
|
||||
@@ -20,7 +20,7 @@ stubsMode = StubRunnerProperties.StubsMode.REMOTE,
|
||||
generateStubs = true)
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.JUnit 4 Rule
|
||||
----
|
||||
@Rule
|
||||
@@ -31,7 +31,7 @@ stubsMode = StubRunnerProperties.StubsMode.REMOTE,
|
||||
.withGenerateStubs(true);
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.JUnit 5 Extension
|
||||
----
|
||||
@RegisterExtension
|
||||
|
||||
@@ -42,19 +42,19 @@ include::{stubrunner_core_path}/src/main/java/org/springframework/cloud/contract
|
||||
The following examples provide more detail about using Stub Runner:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="primary"]
|
||||
.Spock
|
||||
----
|
||||
include::{stubrunner_core_path}/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleSpec.groovy[tags=classrule]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Junit 4
|
||||
----
|
||||
include::{stubrunner_core_path}/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleJUnitTest.java[tags=test]
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.Junit 5
|
||||
----
|
||||
include::{stubrunner_core_path}/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionTests.java[tags=extension]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[features-stub-runner-snapshot-versions]]
|
||||
= Snapshot Versions
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
@@ -8,13 +8,13 @@ You can add the additional snapshot repository to your build file to use snapsho
|
||||
versions, which are automatically uploaded after every successful build, as follows:
|
||||
|
||||
====
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,xml,indent=0,subs="verbatim",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
include::{standalone_samples_path}/http-server/pom.xml[tags=repos,indent=0]
|
||||
----
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
.Gradle (`settings.xml`)
|
||||
----
|
||||
include::{standalone_samples_path}/http-server/settings.gradle[tags=repos,indent=0]
|
||||
|
||||
@@ -18,7 +18,7 @@ In this example, the `producer` project has been successfully
|
||||
built and stubs were generated under the `target/stubs` folder. As a consumer, one can set up the Stub Runner to pick the stubs from that location by using the `stubs://` protocol.
|
||||
|
||||
====
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||
.Annotation
|
||||
----
|
||||
@AutoConfigureStubRunner(
|
||||
@@ -27,7 +27,7 @@ stubsMode = StubRunnerProperties.StubsMode.REMOTE,
|
||||
ids = "com.example:some-producer")
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.JUnit 4 Rule
|
||||
----
|
||||
@Rule
|
||||
@@ -37,7 +37,7 @@ stubsMode = StubRunnerProperties.StubsMode.REMOTE,
|
||||
.stubsMode(StubRunnerProperties.StubsMode.REMOTE);
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.JUnit 5 Extension
|
||||
----
|
||||
@RegisterExtension
|
||||
@@ -76,7 +76,7 @@ The following listing shows an arrangement of contracts and stubs:
|
||||
====
|
||||
|
||||
====
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||
.Annotation
|
||||
----
|
||||
@AutoConfigureStubRunner(
|
||||
@@ -86,7 +86,7 @@ stubsMode = StubRunnerProperties.StubsMode.REMOTE,
|
||||
properties="stubs.find-producer=true")
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.JUnit 4 Rule
|
||||
----
|
||||
static Map<String, String> contractProperties() {
|
||||
@@ -103,7 +103,7 @@ stubsMode = StubRunnerProperties.StubsMode.REMOTE,
|
||||
.properties(contractProperties());
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
.JUnit 5 Extension
|
||||
----
|
||||
static Map<String, String> contractProperties() {
|
||||
|
||||
@@ -7,30 +7,4 @@ This section dives into the details of {project-full-name}. Here you can learn a
|
||||
features that you may want to use and customize. If you have not already done so, you
|
||||
might want to read the "xref:getting-started.adoc[Getting Started]" and
|
||||
"xref:using.adoc[Using Spring Cloud Contract]" sections, so that you have a good grounding in the
|
||||
basics.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[[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
|
||||
xref:howto.adoc[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>>.
|
||||
basics.
|
||||
@@ -9,877 +9,4 @@ cover some {project-full-name} best practices.
|
||||
|
||||
If you are starting out with {project-full-name}, you should probably read the
|
||||
xref:getting-started.adoc[Getting Started] guide before diving into this
|
||||
section.
|
||||
|
||||
[[flows-provider-nexus]]
|
||||
== Provider Contract Testing with Stubs in Nexus or Artifactory
|
||||
|
||||
You can check the xref:getting-started/first-application.adoc[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).
|
||||
|
||||
[[using-prerequisites]]
|
||||
=== 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
|
||||
xref:getting-started/first-application.adoc[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 xref:howto/how-to-use-git-as-storage.adoc[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:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Annotation::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
----
|
||||
@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")
|
||||
----
|
||||
|
||||
JUnit 4 Rule::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
----
|
||||
@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);
|
||||
----
|
||||
|
||||
JUnit 5 Extension::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
----
|
||||
@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:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,role="primary"]
|
||||
----
|
||||
<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>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,role="secondary"]
|
||||
----
|
||||
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
|
||||
xref:howto/how-to-use-git-as-storage.adoc[How To section] of the documentation.
|
||||
|
||||
[[flows-cdc-contracts-producer]]
|
||||
== Consumer Driven Contracts with Contracts on the Producer Side
|
||||
|
||||
See xref:getting-started/cdc.adoc[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]]
|
||||
=== 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 xref:howto/how-to-common-repo-with-contracts.adoc[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:
|
||||
+
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
----
|
||||
<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>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
----
|
||||
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:
|
||||
+
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,bash,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
----
|
||||
./mvnw clean install
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
----
|
||||
./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:
|
||||
+
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
----
|
||||
<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>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
----
|
||||
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 xref:getting-started/cdc.adoc[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
|
||||
xref:using.adoc#flows-provider-git[Provider Contract Testing with Stubs in Git] section.
|
||||
|
||||
You can read more about setting up a git repository for the consumer and producer sides in
|
||||
the xref:howto/how-to-use-git-as-storage.adoc[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 xref:getting-started/first-application.adoc[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);
|
||||
|
||||
[tabs]
|
||||
======
|
||||
JUnit 4 Rule::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
----
|
||||
@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);
|
||||
----
|
||||
|
||||
JUnit 5 Extension::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
----
|
||||
@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:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,role="primary"]
|
||||
----
|
||||
<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>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,role="secondary"]
|
||||
----
|
||||
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:
|
||||
+
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,role="primary"]
|
||||
----
|
||||
<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>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,role="secondary"]
|
||||
----
|
||||
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:
|
||||
+
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,role="primary"]
|
||||
----
|
||||
<!-- 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>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,role="secondary"]
|
||||
----
|
||||
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 xref:getting-started/first-application.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}].
|
||||
section.
|
||||
270
docs/modules/ROOT/pages/using/cdc-external-repo.adoc
Normal file
270
docs/modules/ROOT/pages/using/cdc-external-repo.adoc
Normal file
@@ -0,0 +1,270 @@
|
||||
[[flows-cdc-contracts-external]]
|
||||
= Consumer Driven Contracts with Contracts in an External Repository
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
In this flow, we perform Consumer Driven Contract testing. The contract definitions are
|
||||
stored in a separate repository.
|
||||
|
||||
[[prerequisites]]
|
||||
== 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 xref:../howto/how-to-common-repo-with-contracts.adoc[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:
|
||||
+
|
||||
[tabs]
|
||||
===
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,subs="verbatim",role="primary"]
|
||||
----
|
||||
<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>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
----
|
||||
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:
|
||||
+
|
||||
[tabs]
|
||||
===
|
||||
Maven::
|
||||
+
|
||||
[source,bash,indent=0,subs="verbatim",role="primary"]
|
||||
----
|
||||
./mvnw clean install
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
----
|
||||
./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:
|
||||
+
|
||||
[tabs]
|
||||
===
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,subs="verbatim",role="primary"]
|
||||
----
|
||||
<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>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim",role="secondary"]
|
||||
----
|
||||
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
|
||||
----
|
||||
12
docs/modules/ROOT/pages/using/cdc-git.adoc
Normal file
12
docs/modules/ROOT/pages/using/cdc-git.adoc
Normal file
@@ -0,0 +1,12 @@
|
||||
[[flows-cdc-contracts-stubs-git]]
|
||||
= Consumer-driven Contracts with Contracts on the Producer Side, Pushed to Git
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
You can read the xref:../getting-started/cdc.adoc[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
|
||||
xref:using/provider-contract-testing-with-stubs-in-git.adoc[Provider Contract Testing with Stubs in Git] section.
|
||||
|
||||
You can read more about setting up a git repository for the consumer and producer sides in
|
||||
the xref:../howto/how-to-use-git-as-storage.adoc[How To section] of the documentation.
|
||||
8
docs/modules/ROOT/pages/using/cdc-producer-side.adoc
Normal file
8
docs/modules/ROOT/pages/using/cdc-producer-side.adoc
Normal file
@@ -0,0 +1,8 @@
|
||||
[[flows-cdc-contracts-producer]]
|
||||
= Consumer Driven Contracts with Contracts on the Producer Side
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
See xref:../getting-started/cdc.adoc[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.
|
||||
@@ -0,0 +1,96 @@
|
||||
[[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
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
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
|
||||
----
|
||||
@@ -0,0 +1,160 @@
|
||||
[[flows-provider-non-spring]]
|
||||
= Provider Contract Testing with Stubs in Artifactory for a non-Spring Application
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
In this page you will learn how to do provider contract testing with a non-Spring application and stubs uploaded to Artifactory.
|
||||
|
||||
[[flows-provider-non-spring-flow]]
|
||||
== The Flow
|
||||
|
||||
You can read xref:getting-started/first-application.adoc[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);
|
||||
|
||||
[tabs]
|
||||
===
|
||||
JUnit 4 Rule::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||
----
|
||||
@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);
|
||||
----
|
||||
|
||||
JUnit 5 Extension::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
----
|
||||
@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:
|
||||
|
||||
[tabs]
|
||||
===
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,role="primary"]
|
||||
----
|
||||
<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>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,role="secondary"]
|
||||
----
|
||||
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.
|
||||
@@ -0,0 +1,155 @@
|
||||
[[flows-provider-rest-docs]]
|
||||
= Provider Contract Testing with REST Docs and Stubs in Nexus or Artifactory
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
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:
|
||||
+
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,role="primary"]
|
||||
----
|
||||
<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>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,role="secondary"]
|
||||
----
|
||||
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:
|
||||
+
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,role="primary"]
|
||||
----
|
||||
<!-- 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>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,role="secondary"]
|
||||
----
|
||||
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 xref:getting-started/first-application.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.
|
||||
@@ -0,0 +1,168 @@
|
||||
[[flows-provider-git]]
|
||||
= Provider Contract Testing with Stubs in Git
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
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).
|
||||
|
||||
[[using-prerequisites]]
|
||||
== 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
|
||||
xref:../getting-started/first-application.adoc[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 xref:../howto/how-to-use-git-as-storage.adoc[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:
|
||||
|
||||
[tabs]
|
||||
===
|
||||
Annotation::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim",role="primary"]
|
||||
----
|
||||
@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")
|
||||
----
|
||||
|
||||
JUnit 4 Rule::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
----
|
||||
@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);
|
||||
----
|
||||
|
||||
JUnit 5 Extension::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim",role="secondary"]
|
||||
----
|
||||
@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:
|
||||
|
||||
[tabs]
|
||||
===
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,role="primary"]
|
||||
----
|
||||
<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>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,role="secondary"]
|
||||
----
|
||||
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
|
||||
xref:../howto/how-to-use-git-as-storage.adoc[How To section] of the documentation.
|
||||
@@ -0,0 +1,6 @@
|
||||
[[flows-provider-nexus]]
|
||||
= Provider Contract Testing with Stubs in Nexus or Artifactory
|
||||
|
||||
include::partial$_attributes.adoc[]
|
||||
|
||||
You can check the xref:../getting-started/first-application.adoc[Developing Your First Spring Cloud Contract based application] link to see the provider contract testing with stubs in the Nexus or Artifactory flow.
|
||||
@@ -1,6 +1,6 @@
|
||||
[[yml-schema]]
|
||||
= YML Schema
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
Below you can find a JSON schema definition of a YAML contract.
|
||||
|
||||
|
||||
11
docs/pom.xml
11
docs/pom.xml
@@ -59,6 +59,7 @@
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>src/main/asciidoc</source>
|
||||
<source>src/main/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
@@ -159,6 +160,16 @@
|
||||
<plugin>
|
||||
<groupId>io.spring.maven.antora</groupId>
|
||||
<artifactId>antora-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<packages>
|
||||
<package>@antora/atlas-extension@1.0.0-alpha.1</package>
|
||||
<package>@antora/collector-extension@1.0.0-alpha.3</package>
|
||||
<package>@asciidoctor/tabs@1.0.0-beta.3</package>
|
||||
<package>@springio/antora-extensions@1.5.0</package>
|
||||
<package>@springio/asciidoctor-extensions@1.0.0-alpha.9</package>
|
||||
<package>asciidoctor-kroki@0.17.0</package>
|
||||
</packages>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[spring-cloud-contract]]
|
||||
= Spring Cloud Contract
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
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
|
||||
@@ -10,13 +10,13 @@ producers and consumers -- for both HTTP and message-based interactions.
|
||||
|
||||
[[project-page]]
|
||||
= Project page
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
You can read more about Spring Cloud Contract by going to https://spring.io/projects/spring-cloud-contract[the project page]
|
||||
|
||||
[[contributing]]
|
||||
= Contributing
|
||||
:page-section-summary-toc: 1
|
||||
|
||||
|
||||
include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/docs/src/main/asciidoc/contributing.adoc[]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user