diff --git a/spring-cloud-contract.html b/spring-cloud-contract.html index 8b4b129a6a..9b0d7b7508 100644 --- a/spring-cloud-contract.html +++ b/spring-cloud-contract.html @@ -796,12 +796,28 @@ $(addBlockSwitches); +
  • Pluggable architecture + +
  • +
  • Links
  • -
  • Converters
  • -
  • Stub converters
  • -
  • Example of a custom HTTP Server Stub
  • -
  • Example of a custom Stub Downloader Provider
  • @@ -1592,7 +1608,10 @@ public void shouldBeRejectedDueToAbnormalLoanAmount() {
    -
    Unresolved directive in verifier/introduction.adoc - include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/1.0.x/samples/standalone/dsl/http-client/src/main/java/com/example/loan/LoanApplicationService.java[tags=client_call_server,indent=0]
    +
    ResponseEntity<FraudServiceResponse> response =
    +		restTemplate.exchange("http://localhost:" + port + "/fraudcheck", HttpMethod.PUT,
    +				new HttpEntity<>(request, httpHeaders),
    +				FraudServiceResponse.class);
    @@ -1871,11 +1890,7 @@ It’s really important that you understand the map notation to set up contr
    -
    <dependency>
    -	<groupId>org.springframework.cloud</groupId>
    -	<artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
    -	<scope>test</scope>
    -</dependency>
    +
    Unresolved directive in verifier/introduction.adoc - include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/1.0.x/samples/standalone/dsl/http-client/pom.xml[tags=stub_runner,indent=0]
    @@ -2059,9 +2074,7 @@ public void validate_shouldMarkClientAsFraud() throws Exception { consumes = FRAUD_SERVICE_JSON_VERSION_1, produces = FRAUD_SERVICE_JSON_VERSION_1) public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) { -if (amountGreaterThanThreshold(fraudCheck)) { - return new FraudCheckResult(FraudCheckStatus.FRAUD, AMOUNT_TOO_HIGH); -} +Unresolved directive in verifier/introduction.adoc - include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/1.0.x/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudDetectionController.java[tags=new_impl,indent=0] return new FraudCheckResult(FraudCheckStatus.OK, NO_REASON); }
    @@ -7740,26 +7753,70 @@ common jar classes will be visible in your Groovy files.

    -
    Unresolved directive in verifier/contract.adoc - include::https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer/src/test/resources/contracts/beer/rest/shouldGrantABeerIfOldEnough.groovy[indent=0]
    +
    package contracts.beer.rest
     
    -=== Pluggable architecture
    +import org.springframework.cloud.contract.spec.Contract
     
    -There are cases where you have your contracts defined in other formats
    -like YAML, RAML or PACT. On the other hand you'd like to profit from
    -the test and stubs generation. It's really easy to add your own implementation
    +import static com.example.ConsumerUtils.oldEnough
    +import static com.example.ProducerUtils.ok
    +
    +Contract.make {
    +	request {
    +		description("""
    +Represents a successful scenario of getting a beer
    +
    +given:
    +	client is old enough
    +when:
    +	he applies for a beer
    +then:
    +	we'll grant him the beer
    +""")
    +		method 'POST'
    +		url '/check'
    +		body(
    +				age: $(oldEnough())
    +		)
    +		headers {
    +			contentType(applicationJson())
    +		}
    +	}
    +	response {
    +		status 200
    +		body("""
    +			{
    +				"status": "${value(ok())}"
    +			}
    +			""")
    +		headers {
    +			contentType(applicationJson())
    +		}
    +	}
    +}
    +
    +
    + + + + +
    +

    Pluggable architecture

    +
    +

    There are cases where you have your contracts defined in other formats +like YAML, RAML or PACT. On the other hand you’d like to profit from +the test and stubs generation. It’s really easy to add your own implementation of either of those. Also you can customize the way tests are generated (for example you can generate tests for other languages) and you can do the same for stubs generation (you can generate -stubs for other stub http server implementations). - -==== Custom contract converter - -Let's assume that your contract is written in a YAML file like this: - -[source,yml] -

    +stubs for other stub http server implementations).

    +
    +

    Custom contract converter

    -

    request: +

    Let’s assume that your contract is written in a YAML file like this:

    +
    +
    +
    +
    request:
       url: /foo
       method: PUT
       headers:
    @@ -7771,20 +7828,17 @@ response:
       headers:
         foo2: bar
       body:
    -    foo2: bar

    + foo2: bar
    +
    +
    +
    +

    Thanks to the interface

    -
    Thanks to the interface
    +
    package org.springframework.cloud.contract.spec
     
    -[source,groovy]
    -
    -
    -
    -

    package org.springframework.cloud.contract.spec

    -
    -
    -

    /** +/** * Converter to be used to convert FROM {@link File} TO {@link Contract} * and from {@link Contract} to {@code T} * @@ -7793,138 +7847,120 @@ response: * @author Marcin Grzejszczak * @since 1.1.0 */ -interface ContractConverter<T> {

    -
    -
    -
    -
    /**
    - * Should this file be accepted by the converter. Can use the file extension
    - * to check if the conversion is possible.
    - *
    - * @param file - file to be considered for conversion
    - * @return - {@code true} if the given implementation can convert the file
    - */
    -boolean isAccepted(File file)
    -
    -
    -
    -
    -
    /**
    - * Converts the given {@link File} to its {@link Contract} representation
    - *
    - * @param file - file to convert
    - * @return - {@link Contract} representation of the file
    - */
    -Collection<Contract> convertFrom(File file)
    -
    -
    -
    -
    -
    	/**
    +interface ContractConverter<T> {
    +
    +	/**
    +	 * Should this file be accepted by the converter. Can use the file extension
    +	 * to check if the conversion is possible.
    +	 *
    +	 * @param file - file to be considered for conversion
    +	 * @return - {@code true} if the given implementation can convert the file
    +	 */
    +	boolean isAccepted(File file)
    +
    +	/**
    +	 * Converts the given {@link File} to its {@link Contract} representation
    +	 *
    +	 * @param file - file to convert
    +	 * @return - {@link Contract} representation of the file
    +	 */
    +	Collection<Contract> convertFrom(File file)
    +
    +	/**
     	 * Converts the given {@link Contract} to a {@link T} representation
     	 *
     	 * @param contract - the parsed contract
     	 * @return - {@link T} the type to which we do the conversion
     	 */
     	T convertTo(Collection<Contract> contract)
    -}
    +}
    -
    -
    -
    you can register your own implementation of a contract structure converter.
    +
    +

    you can register your own implementation of a contract structure converter. Your implementation needs to state the condition on which it should start the -conversion. Also you have to define how to perform that conversion in both ways. - -IMPORTANT: Once you create your implementation you have to create a `/META-INF/spring.factories` +conversion. Also you have to define how to perform that conversion in both ways.

    +
    +
    + + + + + +
    +
    Important
    +
    +Once you create your implementation you have to create a /META-INF/spring.factories file in which you provide the fully qualified name of your implementation. - -Example of a `spring.factories` file - -[source] +
    -
    -
    -
    - - - - -

    Converters

    -

    org.springframework.cloud.contract.spec.ContractConverter=\ -org.springframework.cloud.contract.verifier.converter.YamlContractConverter

    +

    Example of a spring.factories file

    -
    and the YAML implementation
    +
    # Converters
    +org.springframework.cloud.contract.spec.ContractConverter=\
    +org.springframework.cloud.contract.verifier.converter.YamlContractConverter
    +
    +
    +
    +

    and the YAML implementation

    +
    +
    +
    +
    package org.springframework.cloud.contract.verifier.converter
     
    -[source,groovy]
    -
    -
    -
    -

    package org.springframework.cloud.contract.verifier.converter

    -
    -
    -

    import groovy.transform.CompileStatic +import groovy.transform.CompileStatic import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.spec.ContractConverter import org.springframework.cloud.contract.spec.internal.Headers -import org.yaml.snakeyaml.Yaml

    -
    -
    -

    /** +import org.yaml.snakeyaml.Yaml + +/** * Simple converter from and to a {@link YamlContract} to a collection of {@link Contract} */ @CompileStatic -class YamlContractConverter implements ContractConverter<List<YamlContract>> {

    -
    -
    -
    -
    @Override
    -public boolean isAccepted(File file) {
    -	String name = file.getName()
    -	return name.endsWith(".yml") || name.endsWith(".yaml")
    -}
    -
    -
    -
    -
    -
    @Override
    -public Collection<Contract> convertFrom(File file) {
    -	try {
    -		YamlContract yamlContract = new Yaml().loadAs(new FileInputStream(file), YamlContract.class)
    -		return [Contract.make {
    -			request {
    -				method(yamlContract?.request?.method)
    -				url(yamlContract?.request?.url)
    -				headers {
    -					yamlContract?.request?.headers?.each { String key, Object value ->
    -						header(key, value)
    -					}
    -				}
    -				body(yamlContract?.request?.body)
    -			}
    -			response {
    -				status(yamlContract?.response?.status)
    -				headers {
    -					yamlContract?.response?.headers?.each { String key, Object value ->
    -						header(key, value)
    -					}
    -				}
    -				body(yamlContract?.response?.body)
    -			}
    -		}]
    +class YamlContractConverter implements ContractConverter<List<YamlContract>> {
    +
    +	@Override
    +	public boolean isAccepted(File file) {
    +		String name = file.getName()
    +		return name.endsWith(".yml") || name.endsWith(".yaml")
     	}
    -	catch (FileNotFoundException e) {
    -		throw new IllegalStateException(e)
    +
    +	@Override
    +	public Collection<Contract> convertFrom(File file) {
    +		try {
    +			YamlContract yamlContract = new Yaml().loadAs(new FileInputStream(file), YamlContract.class)
    +			return [Contract.make {
    +				request {
    +					method(yamlContract?.request?.method)
    +					url(yamlContract?.request?.url)
    +					headers {
    +						yamlContract?.request?.headers?.each { String key, Object value ->
    +							header(key, value)
    +						}
    +					}
    +					body(yamlContract?.request?.body)
    +				}
    +				response {
    +					status(yamlContract?.response?.status)
    +					headers {
    +						yamlContract?.response?.headers?.each { String key, Object value ->
    +							header(key, value)
    +						}
    +					}
    +					body(yamlContract?.response?.body)
    +				}
    +			}]
    +		}
    +		catch (FileNotFoundException e) {
    +			throw new IllegalStateException(e)
    +		}
     	}
    -}
    -
    -
    -
    -
    -
    	@Override
    +
    +	@Override
     	public List<YamlContract> convertTo(Collection<Contract> contracts) {
     		return contracts.collect { Contract contract ->
     			YamlContract yamlContract = new YamlContract()
    @@ -7942,27 +7978,25 @@ public Collection<Contract> convertFrom(File file) {
     			return yamlContract
     		}
     	}
    -}
    +}
    +
    +
    Pact converter
    +
    +

    Spring Cloud Contract comes with an out of the box support for Pact representation of contracts. +In other words instead of using the Groovy DSL you can use Pact files. In this section +we will present how to add such a support for your project.

    +
    +
    +
    Pact contract
    +
    +

    We will be working on the following example of a Pact contract. We’ve placed this file under +the src/test/resources/contracts folder.

    +
    -
    ===== Pact converter
    -
    -Spring Cloud Contract comes with an out of the box support for https://docs.pact.io/[Pact] representation of contracts.
    -In other words instead of using the Groovy DSL you can use Pact files. In this section
    -we will present how to add such a support for your project.
    -
    -====== Pact contract
    -
    -We will be working on the following example of a Pact contract. We've placed this file under
    -the `src/test/resources/contracts` folder.
    -
    -[source,javascript,indent=0]
    -
    -
    -
    -

    { +

    {
       "provider": {
         "name": "Provider"
       },
    @@ -8015,22 +8049,21 @@ the `src/test/resources/contracts` folder.
           "version": "2.4.18"
         }
       }
    -}

    -
    -
    -
    -
    ====== Pact for producers
    -
    -On the producer side you have add to your plugin configuration two additional dependencies.
    -One is the Spring Cloud Contract Pact support and the other represents the current
    -Pact version that you're using.
    -
    -[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
    -.Maven
    +}
    +
    +
    +
    Pact for producers
    -

    <plugin> +

    On the producer side you have add to your plugin configuration two additional dependencies. +One is the Spring Cloud Contract Pact support and the other represents the current +Pact version that you’re using.

    +
    +
    +
    Maven
    +
    +
    <plugin>
     	<groupId>org.springframework.cloud</groupId>
     	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
     	<version>${spring-cloud-contract.version}</version>
    @@ -8050,45 +8083,33 @@ Pact version that you're using.
     			<version>2.4.18</version>
     		</dependency>
     	</dependencies>
    -</plugin>

    +</plugin>
    -
    +
    +
    +
    Gradle
    -
    [source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
    -.Gradle
    +
    classpath "org.springframework.cloud:spring-cloud-contract-spec-pact:${findProperty('verifierVersion') ?: verifierVersion}"
    +classpath 'au.com.dius:pact-jvm-model:2.4.18'
    -

    classpath "org.springframework.cloud:spring-cloud-contract-spec-pact:${findProperty('verifierVersion') ?: verifierVersion}" -classpath 'au.com.dius:pact-jvm-model:2.4.18'

    +

    When you execute the build of your application a test, looking more or less like this, will be generated

    -
    When you execute the build of your application a test, looking more or less like this, will be generated
    -
    -[source,java,indent=0]
    -
    -
    -
    -
    -
    @Test
    +
    @Test
     public void validate_shouldMarkClientAsFraud() throws Exception {
     	// given:
     		MockMvcRequestSpecification request = given()
     				.header("Content-Type", "application/vnd.fraud.v1+json")
    -				.body("{\"clientId\":\"1234567890\",\"loanAmount\":99999}");
    -
    -
    -
    -
    -
    // when:
    -	ResponseOptions response = given().spec(request)
    -			.put("/fraudcheck");
    -
    -
    -
    -
    -
    	// then:
    +				.body("{\"clientId\":\"1234567890\",\"loanAmount\":99999}");
    +
    +	// when:
    +		ResponseOptions response = given().spec(request)
    +				.put("/fraudcheck");
    +
    +	// then:
     		assertThat(response.statusCode()).isEqualTo(200);
     		assertThat(response.header("Content-Type")).isEqualTo("application/vnd.fraud.v1+json;charset=UTF-8");
     	// and:
    @@ -8096,18 +8117,15 @@ public void validate_shouldMarkClientAsFraud() throws Exception {
     		assertThatJson(parsedJson).field("rejectionReason").isEqualTo("Amount too high");
     	// and:
     		assertThat(parsedJson.read("$.fraudCheckStatus", String.class)).matches("FRAUD");
    -}
    -
    -
    -
    -
    -
    and the stub looking like this
    -
    -[source,javascript,indent=0]
    +}
    -

    { +

    and the stub looking like this

    +
    +
    +
    +
    {
       "uuid" : "996ae5ae-6834-4db6-8fac-358ca187ab62",
       "request" : {
         "url" : "/fraudcheck",
    @@ -8130,22 +8148,21 @@ public void validate_shouldMarkClientAsFraud() throws Exception {
           "Content-Type" : "application/vnd.fraud.v1+json;charset=UTF-8"
         }
       }
    -}

    -
    -
    -
    -
    ====== Pact for consumers
    -
    -On the producer side you have add to your project dependencies two additional dependencies.
    -One is the Spring Cloud Contract Pact support and the other represents the current
    -Pact version that you're using.
    -
    -[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
    -.Maven
    +}
    +
    +
    +
    Pact for consumers
    -

    <dependency> +

    On the producer side you have add to your project dependencies two additional dependencies. +One is the Spring Cloud Contract Pact support and the other represents the current +Pact version that you’re using.

    +
    +
    +
    Maven
    +
    +
    <dependency>
     	<groupId>org.springframework.cloud</groupId>
     	<artifactId>spring-cloud-contract-spec-pact</artifactId>
     	<scope>test</scope>
    @@ -8155,51 +8172,46 @@ Pact version that you're using.
     	<artifactId>pact-jvm-model</artifactId>
     	<version>2.4.18</version>
     	<scope>test</scope>
    -</dependency>

    +</dependency>
    +
    +
    +
    +
    Gradle
    +
    +
    testCompile "org.springframework.cloud:spring-cloud-contract-spec-pact"
    +testCompile 'au.com.dius:pact-jvm-model:2.4.18'
    +
    +
    +
    +
    +
    +
    +

    Custom test generator

    +
    +

    If you want to generate tests for different languages than Java or you’re +not happy with the way we’re building Java tests for you then you can register +your own implementation to do that.

    +
    +
    +

    Thanks to the interface

    -
    [source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
    -.Gradle
    -
    -
    -
    -

    testCompile "org.springframework.cloud:spring-cloud-contract-spec-pact" -testCompile 'au.com.dius:pact-jvm-model:2.4.18'

    -
    -
    -
    -
    ==== Custom test generator
    +
    package org.springframework.cloud.contract.verifier.builder
     
    -If you want to generate tests for different languages than Java or you're
    -not happy with the way we're building Java tests for you then you can register
    -your own implementation to do that.
    -
    -Thanks to the interface
    -
    -[source,groovy]
    -
    -
    -
    -

    package org.springframework.cloud.contract.verifier.builder

    -
    -
    -

    import groovy.transform.CompileStatic +import groovy.transform.CompileStatic import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties -import org.springframework.cloud.contract.verifier.file.ContractMetadata

    -
    -
    -

    /** +import org.springframework.cloud.contract.verifier.file.ContractMetadata + +/** * Builds a single test. * * @since 1.1.0 */ @CompileStatic -interface SingleTestGenerator {

    -
    -
    -
    -
    	/**
    +interface SingleTestGenerator {
    +
    +	/**
     	 * Creates contents of a single test class in which all test scenarios from
     	 * the contract metadata should be placed.
     	 *
    @@ -8212,68 +8224,54 @@ interface SingleTestGenerator {

    */ String buildClass(ContractVerifierConfigProperties properties, Collection<ContractMetadata> listOfFiles, String className, String classPackage, String includedDirectoryRelativePath) -}
    +}
    +
    +

    you can register your own implementation that generates a test. Again, it’s enough to provide +a proper spring.factories file. Example:

    +
    -
    you can register your own implementation that generates a test. Again, it's enough to provide
    -a proper `spring.factories` file. Example:
    -
    -[source]
    +
    org.springframework.cloud.contract.verifier.builder.SingleTestGenerator=/
    +com.example.MyGenerator
    +
    +
    +

    Custom stub generator

    -

    org.springframework.cloud.contract.verifier.builder.SingleTestGenerator=/ -com.example.MyGenerator

    +

    If you want to generate stubs for other stub server than WireMock it’s enough to + plug in your own implementation of this interface:

    -
    ==== Custom stub generator
    +
    package org.springframework.cloud.contract.verifier.converter
     
    -If you want to generate stubs for other stub server than WireMock it's enough to
    - plug in your own implementation of this interface:
    -
    -[source,groovy]
    -
    -
    -
    -

    package org.springframework.cloud.contract.verifier.converter

    -
    -
    -

    import groovy.transform.CompileStatic +import groovy.transform.CompileStatic import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.file.ContractMetadata

    -
    -
    -

    /** +import org.springframework.cloud.contract.verifier.file.ContractMetadata + +/** * Converts contracts into their stub representation. * * @since 1.1.0 */ @CompileStatic -interface StubGenerator {

    -
    -
    -
    -
    /**
    - * Returns {@code true} if the converter can handle the file to convert it into a stub.
    - */
    -boolean canHandleFileName(String fileName)
    -
    -
    -
    -
    -
    /**
    - * Returns the collection of converted contracts into stubs. One contract can
    - * result in multiple stubs.
    - */
    -Map<Contract, String> convertContents(String rootName, ContractMetadata content)
    -
    -
    -
    -
    -
    	/**
    +interface StubGenerator {
    +
    +	/**
    +	 * Returns {@code true} if the converter can handle the file to convert it into a stub.
    +	 */
    +	boolean canHandleFileName(String fileName)
    +
    +	/**
    +	 * Returns the collection of converted contracts into stubs. One contract can
    +	 * result in multiple stubs.
    +	 */
    +	Map<Contract, String> convertContents(String rootName, ContractMetadata content)
    +
    +	/**
     	 * Returns the name of the converted stub file. If you have multiple contracts
     	 * in a single file then a prefix will be added to the generated file. If you
     	 * provide the {@link Contract#name} field then that field will override the
    @@ -8284,246 +8282,220 @@ Map<Contract, String> convertContents(String rootName, ContractMetadata co
     	 * converter will create two files {@code 0_foo.json} and {@code 1_foo.json}
     	 */
     	String generateOutputFileNameForInput(String inputFileName)
    -}
    +}
    -
    -
    -
    you can register your own implementation that generate Stubs. Again, it's enough to provide
    -a proper `spring.factories` file. Example:
    -
    -[source]
    -
    -
    -

    Stub converters

    -

    org.springframework.cloud.contract.verifier.converter.StubGenerator=\ -org.springframework.cloud.contract.verifier.wiremock.DslToWireMockClientConverter

    +

    you can register your own implementation that generate Stubs. Again, it’s enough to provide +a proper spring.factories file. Example:

    -
    The default implementation is the WireMock stub generation.
    -
    -TIP: You can provide multiple stub generator implementations. That way for example from a single
    +
    # Stub converters
    +org.springframework.cloud.contract.verifier.converter.StubGenerator=\
    +org.springframework.cloud.contract.verifier.wiremock.DslToWireMockClientConverter
    +
    +
    +
    +

    The default implementation is the WireMock stub generation.

    +
    +
    + + + + + +
    +
    Tip
    +
    +You can provide multiple stub generator implementations. That way for example from a single DSL as input you can e.g. produce WireMock stubs and Pact files too! - -==== Custom Stub Runner - -If you decide to have a custom stub generation you also need a custom way of running -stubs with your different stub provider. - -Let us assume that you're using https://github.com/dreamhead/moco[Moco] to build your stubs. -You wrote a proper stub generator and your stubs got placed 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. It can look like this: - -[source,groovy] +
    +
    +

    Custom Stub Runner

    +
    +

    If you decide to have a custom stub generation you also need a custom way of running +stubs with your different stub provider.

    +
    -

    package org.springframework.cloud.contract.stubrunner.provider.moco

    +

    Let us assume that you’re using Moco to build your stubs. +You wrote a proper stub generator and your stubs got placed in a JAR file.

    -

    import com.github.dreamhead.moco.bootstrap.arg.HttpArgs +

    In order for Stub Runner to know how to run your stubs you have to define a custom + HTTP Stub server implementation. It can look like this:

    +
    +
    +
    +
    package org.springframework.cloud.contract.stubrunner.provider.moco
    +
    +import com.github.dreamhead.moco.bootstrap.arg.HttpArgs
     import com.github.dreamhead.moco.runner.JsonRunner
     import org.springframework.cloud.contract.stubrunner.HttpServerStub
    -import org.springframework.util.SocketUtils

    -
    -
    -

    class MocoHttpServerStub implements HttpServerStub {

    -
    -
    -
    -
    private boolean started
    -private JsonRunner runner
    -private int port
    -
    -
    -
    -
    -
    @Override
    -int port() {
    -	if (!isRunning()) {
    -		return -1
    +import org.springframework.util.SocketUtils
    +
    +class MocoHttpServerStub implements HttpServerStub {
    +
    +	private boolean started
    +	private JsonRunner runner
    +	private int port
    +
    +	@Override
    +	int port() {
    +		if (!isRunning()) {
    +			return -1
    +		}
    +		return port
     	}
    -	return port
    -}
    -
    -
    -
    -
    -
    @Override
    -boolean isRunning() {
    -	return started
    -}
    -
    -
    -
    -
    -
    @Override
    -HttpServerStub start() {
    -	return start(SocketUtils.findAvailableTcpPort())
    -}
    -
    -
    -
    -
    -
    @Override
    -HttpServerStub start(int port) {
    -	this.port = port
    -	return this
    -}
    -
    -
    -
    -
    -
    @Override
    -HttpServerStub stop() {
    -	if (!isRunning()) {
    +
    +	@Override
    +	boolean isRunning() {
    +		return started
    +	}
    +
    +	@Override
    +	HttpServerStub start() {
    +		return start(SocketUtils.findAvailableTcpPort())
    +	}
    +
    +	@Override
    +	HttpServerStub start(int port) {
    +		this.port = port
     		return this
     	}
    -	this.runner.stop()
    -	return this
    -}
    -
    -
    -
    -
    -
    @Override
    -HttpServerStub registerMappings(Collection<File> stubFiles) {
    -	List<InputStream> streams = stubFiles.collect { it.newInputStream() }
    -	this.runner = JsonRunner.newJsonRunnerWithStreams(streams,
    -			HttpArgs.httpArgs().withPort(this.port).build())
    -	this.runner.run()
    -	this.started = true
    -	return this
    -}
    -
    -
    -
    -
    -
    	@Override
    +
    +	@Override
    +	HttpServerStub stop() {
    +		if (!isRunning()) {
    +			return this
    +		}
    +		this.runner.stop()
    +		return this
    +	}
    +
    +	@Override
    +	HttpServerStub registerMappings(Collection<File> stubFiles) {
    +		List<InputStream> streams = stubFiles.collect { it.newInputStream() }
    +		this.runner = JsonRunner.newJsonRunnerWithStreams(streams,
    +				HttpArgs.httpArgs().withPort(this.port).build())
    +		this.runner.run()
    +		this.started = true
    +		return this
    +	}
    +
    +	@Override
     	boolean isAccepted(File file) {
     		return file.name.endsWith(".json")
     	}
    -}
    +}
    -
    -
    -
    and just register it in your `spring.factories` file
    -
    -[source]
    -
    -
    -

    Example of a custom HTTP Server Stub

    -

    org.springframework.cloud.contract.stubrunner.HttpServerStub=\ -org.springframework.cloud.contract.stubrunner.provider.moco.MocoHttpServerStub

    +

    and just register it in your spring.factories file

    -
    that way you'll be able to run stubs using Moco.
    -
    -IMPORTANT: If you don't provide any implementation then the default one - WireMock based
    +
    # Example of a custom HTTP Server Stub
    +org.springframework.cloud.contract.stubrunner.HttpServerStub=\
    +org.springframework.cloud.contract.stubrunner.provider.moco.MocoHttpServerStub
    +
    +
    +
    +

    that way you’ll be able to run stubs using Moco.

    +
    +
    + + + + + +
    +
    Important
    +
    +If you don’t provide any implementation then the default one - WireMock based will be picked. If you provide more than one then the first one on the list will be picked. - -==== Custom Stub Downloader - -You can customize the way your stubs are downloaded. If you don't want to download the JARs +
    +
    +
    +
    +

    Custom Stub Downloader

    +
    +

    You can customize the way your stubs are downloaded. If you don’t want to download the JARs from Nexus / Artifactory in the way we do by default you can set your own implementation. -Below you can find an example of a Stub Downloader Provider that takes `json` files from the test resources +Below you can find an example of a Stub Downloader Provider that takes json files from the test resources from classpath, copies them to a temp file and then passes that temporary folder - as a root for the stubs. + as a root for the stubs.

    +
    +
    +
    +
    package org.springframework.cloud.contract.stubrunner.provider.moco
     
    -[source,java]
    -
    -
    -
    -

    package org.springframework.cloud.contract.stubrunner.provider.moco

    -
    -
    -

    import org.springframework.cloud.contract.stubrunner.StubConfiguration +import org.springframework.cloud.contract.stubrunner.StubConfiguration import org.springframework.cloud.contract.stubrunner.StubDownloader import org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder import org.springframework.cloud.contract.stubrunner.StubRunnerOptions import org.springframework.core.io.DefaultResourceLoader import org.springframework.core.io.Resource -import org.springframework.core.io.support.PathMatchingResourcePatternResolver

    -
    -
    -

    import java.nio.file.Files

    -
    -
    -

    /** - * Poor man’s version of taking stubs from classpath. It needs much more +import org.springframework.core.io.support.PathMatchingResourcePatternResolver + +import java.nio.file.Files + +/** + * Poor man's version of taking stubs from classpath. It needs much more * love and attention to go to the main sources. * * @author Marcin Grzejszczak */ -class ClasspathStubProvider implements StubDownloaderBuilder {

    -
    -
    -
    -
    private static final int TEMP_DIR_ATTEMPTS = 10000
    -
    -
    -
    -
    -
    @Override
    -public StubDownloader build(StubRunnerOptions stubRunnerOptions) {
    -	final StubConfiguration configuration = stubRunnerOptions.getDependencies().first()
    -	PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(
    -			new DefaultResourceLoader())
    -	try {
    -		String rootFolder = repoRoot(stubRunnerOptions) ?: "**/" + separatedArtifact(configuration) + "/**/*.json"
    -		Resource[] resources = resolver.getResources(rootFolder)
    -		final File tmp = createTempDir()
    -		tmp.deleteOnExit()
    -		// you'd have to write an impl to maintain the folder structure
    -		// this is just for demo
    -		resources.each { Resource resource ->
    -			Files.copy(resource.getInputStream(), new File(tmp, resource.getFile().getName()).toPath())
    -		}
    -		return new StubDownloader() {
    -			@Override
    -			public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
    -					StubConfiguration stubConfiguration) {
    -				return new AbstractMap.SimpleEntry(configuration, tmp)
    +class ClasspathStubProvider implements StubDownloaderBuilder {
    +
    +	private static final int TEMP_DIR_ATTEMPTS = 10000
    +
    +	@Override
    +	public StubDownloader build(StubRunnerOptions stubRunnerOptions) {
    +		final StubConfiguration configuration = stubRunnerOptions.getDependencies().first()
    +		PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(
    +				new DefaultResourceLoader())
    +		try {
    +			String rootFolder = repoRoot(stubRunnerOptions) ?: "**/" + separatedArtifact(configuration) + "/**/*.json"
    +			Resource[] resources = resolver.getResources(rootFolder)
    +			final File tmp = createTempDir()
    +			tmp.deleteOnExit()
    +			// you'd have to write an impl to maintain the folder structure
    +			// this is just for demo
    +			resources.each { Resource resource ->
    +				Files.copy(resource.getInputStream(), new File(tmp, resource.getFile().getName()).toPath())
     			}
    +			return new StubDownloader() {
    +				@Override
    +				public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
    +						StubConfiguration stubConfiguration) {
    +					return new AbstractMap.SimpleEntry(configuration, tmp)
    +				}
    +			}
    +		} catch (IOException e) {
    +			throw new IllegalStateException(e)
     		}
    -	} catch (IOException e) {
    -		throw new IllegalStateException(e)
     	}
    -}
    -
    -
    -
    -
    -
    private String repoRoot(StubRunnerOptions stubRunnerOptions) {
    -	switch (stubRunnerOptions.stubRepositoryRoot) {
    -		case { !it }:
    -			return ""
    -		case { String root -> root.endsWith("**/*.json") }:
    -			return stubRunnerOptions.stubRepositoryRoot
    -		default:
    -			return stubRunnerOptions.stubRepositoryRoot + "/**/*.json"
    +
    +	private String repoRoot(StubRunnerOptions stubRunnerOptions) {
    +		switch (stubRunnerOptions.stubRepositoryRoot) {
    +			case { !it }:
    +				return ""
    +			case { String root -> root.endsWith("**/*.json") }:
    +				return stubRunnerOptions.stubRepositoryRoot
    +			default:
    +				return stubRunnerOptions.stubRepositoryRoot + "/**/*.json"
    +		}
     	}
    -}
    -
    -
    -
    -
    -
    private String separatedArtifact(StubConfiguration configuration) {
    -	return configuration.getGroupId().replace(".", File.separator) +
    -			File.separator + configuration.getArtifactId()
    -}
    -
    -
    -
    -
    -
    	// Taken from Guava
    +
    +	private String separatedArtifact(StubConfiguration configuration) {
    +		return configuration.getGroupId().replace(".", File.separator) +
    +				File.separator + configuration.getArtifactId()
    +	}
    +
    +	// Taken from Guava
     	private File createTempDir() {
     		File baseDir = new File(System.getProperty("java.io.tmpdir"))
     		String baseName = System.currentTimeMillis() + "-"
    @@ -8537,40 +8509,71 @@ public StubDownloader build(StubRunnerOptions stubRunnerOptions) {
     				"Failed to create directory within " + TEMP_DIR_ATTEMPTS + " attempts (tried " + baseName + "0 to " + baseName + (
     						TEMP_DIR_ATTEMPTS - 1) + ")")
     	}
    -}
    +}
    -
    -
    -
    and just register it in your `spring.factories` file
    -
    -[source]
    -
    -
    -

    Example of a custom Stub Downloader Provider

    -

    org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder=\ -org.springframework.cloud.contract.stubrunner.provider.moco.ClasspathStubProvider

    +

    and just register it in your spring.factories file

    -
    that way you'll be able to pick a folder with the source of your stubs.
    -
    -IMPORTANT: If you don't provide any implementation then the default one - Aether based that will download stubs from a remote repo
    +
    # Example of a custom Stub Downloader Provider
    +org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder=\
    +org.springframework.cloud.contract.stubrunner.provider.moco.ClasspathStubProvider
    +
    +
    +
    +

    that way you’ll be able to pick a folder with the source of your stubs.

    +
    +
    + + + + + +
    +
    Important
    +
    +If you don’t provide any implementation then the default one - Aether based that will download stubs from a remote repo will be picked. If you provide more than one then the first one on the list will be picked. - -=== Links - -Here you can find interesting links related to Spring Cloud Contract Verifier: - -- https://github.com/spring-cloud/spring-cloud-contract/[Spring Cloud Contract Github Repository] -- https://github.com/spring-cloud-samples/spring-cloud-contract-samples/[Spring Cloud Contract Samples] -- https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html[Spring Cloud Contract Documentation] -- https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html/deprecated[Accurest Legacy Documentation] -- https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html/#spring-cloud-contract-stub-runner[Spring Cloud Contract Stub Runner Documentation] -- https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html/#stub-runner-for-messaging[Spring Cloud Contract Stub Runner Messaging Documentation] -- https://gitter.im/spring-cloud/spring-cloud-contract[Spring Cloud Contract Gitter] -- https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract-maven-plugin/[Spring Cloud Contract Maven Plugin] +
    +
    +
    +
    +
    + +
    +

    Here you can find interesting links related to Spring Cloud Contract Verifier:

    +
    + +