diff --git a/docs/src/main/asciidoc/_project-features-contract.adoc b/docs/src/main/asciidoc/_project-features-contract.adoc index 45a90de82f..888208d444 100644 --- a/docs/src/main/asciidoc/_project-features-contract.adoc +++ b/docs/src/main/asciidoc/_project-features-contract.adoc @@ -69,6 +69,7 @@ The following sections describe the most common top-level elements: * <> * <> * <> +* <> * <> [[contract-dsl-description]] @@ -141,6 +142,30 @@ include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=ignored,i ---- ==== +[[contract-dsl-in-progress]] +==== Contracts in Progress + +A contract in progress will not generate tests on the producer side, but will allow generation of stubs. + +IMPORTANT: Use this feature with caution as it may lead to false positives. You generate stubs for your consumers to use without actually having the implementation in place! + +If you want to set a contract in progress the following +example shows how to do so: + +==== +[source,groovy,indent=0,role="primary"] +.groovy +---- +include::{contract_spec_tests_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=in_progress,indent=0] +---- + +[source,yaml,indent=0,role="secondary"] +.yml +---- +include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=in_progress,indent=0] +---- +==== + [[contract-dsl-passing-values-from-files]] ==== Passing Values from Files diff --git a/docs/src/main/asciidoc/_project-features-stubrunner.adoc b/docs/src/main/asciidoc/_project-features-stubrunner.adoc index 508e1fa2e4..e125eeccec 100644 --- a/docs/src/main/asciidoc/_project-features-stubrunner.adoc +++ b/docs/src/main/asciidoc/_project-features-stubrunner.adoc @@ -972,6 +972,49 @@ stubsMode = StubRunnerProperties.StubsMode.REMOTE, ---- ==== +[[features-stub-runner-generate-stubs-at-runtime]] +=== Generating Stubs at Runtime + +As a consumer, you might not want to wait for the producer to finish its implementation and then publish their stubs. A solution to this problem can be generation of stubs at runtime. + +As a producer, when a contract is defined, you are required to make the generated tests pass in order for the stubs to be published. There are cases where you would like to unblock the consumers so that they can fetch the stubs before your tests are actually passing. In this case you should set such contracts as in progress. You can read more about this under the <> section. That way your tests will not be generated, but the stubs will. + +As a consumer, you can toggle a switch to generate stubs at runtime. Stub Runner will ignore all the existing stub mappings and will generate new ones for all the contract definitions. Another option is to pass the `stubrunner.generate-stubs` system property. Below you can find an example of such setup. + +==== +[source,java,indent=0,subs="verbatim,attributes",role="primary"] +.Annotation +---- +@AutoConfigureStubRunner( +stubsMode = StubRunnerProperties.StubsMode.REMOTE, + repositoryRoot = "stubs://file://location/to/the/contracts", + ids = "com.example:some-producer", + generateStubs = true) +---- + +[source,java,indent=0,subs="verbatim,attributes",role="secondary"] +.JUnit 4 Rule +---- +@Rule + public StubRunnerRule rule = new StubRunnerRule() + .downloadStub("com.example:some-producer") + .repoRoot("stubs://file://location/to/the/contracts") + .stubsMode(StubRunnerProperties.StubsMode.REMOTE) + .withGenerateStubs(true); +---- + +[source,java,indent=0,subs="verbatim,attributes",role="secondary"] +.JUnit 5 Extension +---- +@RegisterExtension + public StubRunnerExtension stubRunnerExtension = new StubRunnerExtension() + .downloadStub("com.example:some-producer") + .repoRoot("stubs://file://location/to/the/contracts") + .stubsMode(StubRunnerProperties.StubsMode.REMOTE) + .withGenerateStubs(true); +---- +==== + [[features-stub-runner-common]] === Common Properties diff --git a/docs/src/main/asciidoc/howto.adoc b/docs/src/main/asciidoc/howto.adoc index 2de28179b4..6aaa45f9fe 100644 --- a/docs/src/main/asciidoc/howto.adoc +++ b/docs/src/main/asciidoc/howto.adoc @@ -1436,4 +1436,9 @@ TIP: You need not specify the output directory for the generated snippets (since [[how-to-use-stubs-from-a-location]] == How can I Use Stubs from a Location -If you want to fetch contracts or stubs from a given location without cloning a repo or fetching a JAR, just use the `stubs://` protocol when providing the repository root argument for Stub Runner or the Spring Cloud Contract plugin. You can read more about this in <> of the documentation. \ No newline at end of file +If you want to fetch contracts or stubs from a given location without cloning a repo or fetching a JAR, just use the `stubs://` protocol when providing the repository root argument for Stub Runner or the Spring Cloud Contract plugin. You can read more about this in <> of the documentation. + +[[how-to-generate-stubs-at-runtime]] +== How can I Generate Stubs at Runtime + +If you want to generate stubs at runtime for contracts, it's enough to switch the `generateStubs` property in the `@AutoConfigureStubRunner` annotation, or call the `withGenerateStubs()` method on the JUnit Rule or Extension. You can read more about this in <> of the documentation. \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy b/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy index 41c3741742..e0a7a4a3e2 100644 --- a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy +++ b/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy @@ -211,6 +211,15 @@ then: // end::ignored[] } + def 'should mark a contract in progress'() { + given: + // tag::in_progress[] + org.springframework.cloud.contract.spec.Contract.make { + inProgress() + } + // end::in_progress[] + } + def 'should make equals and hashcode work properly for URL'() { expect: def a = Contract.make { diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverterSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverterSpec.groovy index d948b4ab54..e558aac2d8 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverterSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverterSpec.groovy @@ -799,6 +799,7 @@ inProgress: false and: List contracts = [Contract.make { request { + inProgress() url("/foo") method("PUT") headers { @@ -828,6 +829,7 @@ inProgress: false then: yamlContracts.size() == 1 YamlContract yamlContract = yamlContracts.first() + yamlContract.inProgress == true yamlContract.request.url == "/foo" yamlContract.request.method == "PUT" yamlContract.request.headers.find { it.key == "foo" && it.value == "bar" } diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract.yml index 6f1a02c319..f7f47657c1 100644 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract.yml +++ b/spring-cloud-contract-verifier/src/test/resources/yml/contract.yml @@ -10,6 +10,9 @@ priority: 8 #tag::ignored[] ignored: true #end::ignored[] +#tag::in_progress[] +inProgress: true +#end::in_progress[] #tag::request[] request: #end::request[]