Files
spring-cloud-static/Greenwich.SR1/multi/multi__using_the_pluggable_architecture.html
2019-03-06 10:23:45 -05:00

471 lines
55 KiB
HTML

<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>95.&nbsp;Using the Pluggable Architecture</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_contract.html" title="Part&nbsp;XIII.&nbsp;Spring Cloud Contract"><link rel="prev" href="multi__customization.html" title="94.&nbsp;Customization"><link rel="next" href="multi__spring_cloud_contract_wiremock.html" title="96.&nbsp;Spring Cloud Contract WireMock"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">95.&nbsp;Using the Pluggable Architecture</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__customization.html">Prev</a>&nbsp;</td><th width="60%" align="center">Part&nbsp;XIII.&nbsp;Spring Cloud Contract</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="multi__spring_cloud_contract_wiremock.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_using_the_pluggable_architecture" href="#_using_the_pluggable_architecture"></a>95.&nbsp;Using the Pluggable Architecture</h2></div></div></div><p>You may encounter cases where you have 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).</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_custom_contract_converter" href="#_custom_contract_converter"></a>95.1&nbsp;Custom Contract Converter</h2></div></div></div><p>The <code class="literal">ContractConverter</code> interface lets you register your own implementation of a contract
structure converter. The following code listing shows the <code class="literal">ContractConverter</code> interface:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> org.springframework.cloud.contract.spec
<strong class="hl-tag" style="color: blue">/**
* Converter to be used to convert FROM {@link File} TO {@link Contract}
* and from {@link Contract} to {@code T}
*
* @param &lt;T &gt; - type to which we want to convert the contract
*
* @author Marcin Grzejszczak
* @since 1.1.0
*/</strong>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> ContractConverter&lt;T&gt; <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> ContractStorer&lt;T&gt; {
<strong class="hl-tag" style="color: blue">/**
* 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
*/</strong>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> isAccepted(File file)
<strong class="hl-tag" style="color: blue">/**
* Converts the given {@link File} to its {@link Contract} representation
*
* @param file - file to convert
* @return - {@link Contract} representation of the file
*/</strong>
Collection&lt;Contract&gt; convertFrom(File file)
<strong class="hl-tag" style="color: blue">/**
* 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
*/</strong>
T convertTo(Collection&lt;Contract&gt; contract)
}</pre><p>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.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>Once you create your implementation, you must create a
<code class="literal">/META-INF/spring.factories</code> file in which you provide the fully qualified name of your
implementation.</p></td></tr></table></div><p>The following example shows a typical <code class="literal">spring.factories</code> file:</p><pre class="screen">org.springframework.cloud.contract.spec.ContractConverter=\
org.springframework.cloud.contract.verifier.converter.YamlContractConverter</pre><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="pact-converter" href="#pact-converter"></a>95.1.1&nbsp;Pact Converter</h3></div></div></div><p>Spring Cloud Contract includes support for <a class="link" href="https://docs.pact.io/" target="_top">Pact</a> representation of
contracts up until v4. Instead of using the Groovy DSL, you can use Pact files. In this section, we
present how to add Pact support for your project. Note however that not all functionality is supported.
Starting with v3 you can combine multiple matcher for the same element;
you can use matchers for the body, headers, request and path; and you can use value generators.
Spring Cloud Contract currently only supports multiple matchers that are combined using the AND rule logic.
Next to that the request and path matchers are skipped during the conversion.
When using a date, time or datetime value generator with a given format,
the given format will be skipped and the ISO format will be used.</p><p>In order to properly support the Spring Cloud Contract way of doing messaging
with Pact you&#8217;ll have to provide some additional meta data entries. Below you can find a list of such entries:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">to define the destination to which a message gets sent, you have to
set a <code class="literal">metaData</code> entry in the Pact file, with key <code class="literal">sentTo</code> equal to the destination to which a message is to be sent. E.g. <code class="literal">"metaData": { "sentTo": "activemq:output" }</code></li></ul></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_pact_contract" href="#_pact_contract"></a>95.1.2&nbsp;Pact Contract</h3></div></div></div><p>Consider following example of a Pact contract, which is a file under the
<code class="literal">src/test/resources/contracts</code> folder.</p><pre class="programlisting">{
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"provider"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"name"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Provider"</span>
},
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"consumer"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"name"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Consumer"</span>
},
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"interactions"</span>: [
{
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"description"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">""</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"request"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"method"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"PUT"</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"path"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/fraudcheck"</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"headers"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Content-Type"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"application/vnd.fraud.v1+json"</span>
},
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"body"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"clientId"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"1234567890"</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"loanAmount"</span>: <span class="hl-number">99999</span>
},
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"generators"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"body"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"$.clientId"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"type"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Regex"</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"regex"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"[0-9]{10}"</span>
}
}
},
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"matchingRules"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"header"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Content-Type"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"matchers"</span>: [
{
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"match"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"regex"</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"regex"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"application/vnd\\.fraud\\.v1\\+json.*"</span>
}
],
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"combine"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"AND"</span>
}
},
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"body"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"$.clientId"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"matchers"</span>: [
{
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"match"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"regex"</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"regex"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"[0-9]{10}"</span>
}
],
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"combine"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"AND"</span>
}
}
}
},
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"response"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"status"</span>: <span class="hl-number">200</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"headers"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Content-Type"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"application/vnd.fraud.v1+json;charset=UTF-8"</span>
},
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"body"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"fraudCheckStatus"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"FRAUD"</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"rejectionReason"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Amount too high"</span>
},
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"matchingRules"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"header"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Content-Type"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"matchers"</span>: [
{
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"match"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"regex"</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"regex"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"application/vnd\\.fraud\\.v1\\+json.*"</span>
}
],
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"combine"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"AND"</span>
}
},
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"body"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"$.fraudCheckStatus"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"matchers"</span>: [
{
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"match"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"regex"</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"regex"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"FRAUD"</span>
}
],
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"combine"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"AND"</span>
}
}
}
}
}
],
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"metadata"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"pact-specification"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"version"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"3.0.0"</span>
},
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"pact-jvm"</span>: {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"version"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"3.5.13"</span>
}
}
}</pre><p>The remainder of this section about using Pact refers to the preceding file.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_pact_for_producers" href="#_pact_for_producers"></a>95.1.3&nbsp;Pact for Producers</h3></div></div></div><p>On the producer side, you must add two additional dependencies to your plugin
configuration. One is the Spring Cloud Contract Pact support, and the other represents
the current Pact version that you use.</p><p class="primary"><b>Maven.&nbsp;</b>
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;plugin&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;groupId&gt;</span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/groupId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;artifactId&gt;</span>spring-cloud-contract-maven-plugin<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/artifactId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;version&gt;</span>${spring-cloud-contract.version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/version&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;extensions&gt;</span>true<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/extensions&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;configuration&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;packageWithBaseClasses&gt;</span>com.example.fraud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/packageWithBaseClasses&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/configuration&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;dependencies&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;dependency&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;groupId&gt;</span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/groupId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;artifactId&gt;</span>spring-cloud-contract-pact<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/artifactId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;version&gt;</span>${spring-cloud-contract.version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/version&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/dependency&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/dependencies&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/plugin&gt;</span></pre><p class="primary">
</p><p class="secondary"><b>Gradle.&nbsp;</b>
</p><pre class="programlisting">classpath <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"org.springframework.cloud:spring-cloud-contract-pact:${findProperty('verifierVersion') ?: verifierVersion}"</span></pre><p class="secondary">
</p><p>When you execute the build of your application, a test will be generated. The generated
test might be as follows:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Test</span></em>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> validate_shouldMarkClientAsFraud() <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// given:</span>
MockMvcRequestSpecification request = given()
.header(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Content-Type"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"application/vnd.fraud.v1+json"</span>)
.body(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"{\"clientId\":\"1234567890\",\"loanAmount\":99999}"</span>);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// when:</span>
ResponseOptions response = given().spec(request)
.put(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/fraudcheck"</span>);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// then:</span>
assertThat(response.statusCode()).isEqualTo(<span class="hl-number">200</span>);
assertThat(response.header(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Content-Type"</span>)).matches(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"application/vnd\\.fraud\\.v1\\+json.*"</span>);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// and:</span>
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).field(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"['rejectionReason']"</span>).isEqualTo(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Amount too high"</span>);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// and:</span>
assertThat(parsedJson.read(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"$.fraudCheckStatus"</span>, String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>)).matches(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"FRAUD"</span>);
}</pre><p>The corresponding generated stub might be as follows:</p><pre class="programlisting">{
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"id"</span> : <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"996ae5ae-6834-4db6-8fac-358ca187ab62"</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"uuid"</span> : <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"996ae5ae-6834-4db6-8fac-358ca187ab62"</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"request"</span> : {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"url"</span> : <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/fraudcheck"</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"method"</span> : <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"PUT"</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"headers"</span> : {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Content-Type"</span> : {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"matches"</span> : <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"application/vnd\\.fraud\\.v1\\+json.*"</span>
}
},
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"bodyPatterns"</span> : [ {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"matchesJsonPath"</span> : <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"$[?(@.['loanAmount'] == 99999)]"</span>
}, {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"matchesJsonPath"</span> : <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"$[?(@.clientId =~ /([0-9]{10})/)]"</span>
} ]
},
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"response"</span> : {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"status"</span> : <span class="hl-number">200</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"body"</span> : <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}"</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"headers"</span> : {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Content-Type"</span> : <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"application/vnd.fraud.v1+json;charset=UTF-8"</span>
},
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"transformers"</span> : [ <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"response-template"</span> ]
},
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_pact_for_consumers" href="#_pact_for_consumers"></a>95.1.4&nbsp;Pact for Consumers</h3></div></div></div><p>On the producer side, you must add two additional dependencies to your project
dependencies. One is the Spring Cloud Contract Pact support, and the other represents the
current Pact version that you use.</p><p class="primary"><b>Maven.&nbsp;</b>
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;dependency&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;groupId&gt;</span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/groupId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;artifactId&gt;</span>spring-cloud-contract-pact<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/artifactId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;scope&gt;</span>test<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/scope&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/dependency&gt;</span></pre><p class="primary">
</p><p class="secondary"><b>Gradle.&nbsp;</b>
</p><pre class="programlisting">testCompile <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"org.springframework.cloud:spring-cloud-contract-pact"</span></pre><p class="secondary">
</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_using_the_custom_test_generator" href="#_using_the_custom_test_generator"></a>95.2&nbsp;Using the Custom Test Generator</h2></div></div></div><p>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.</p><p>The <code class="literal">SingleTestGenerator</code> interface lets you register your own implementation. The
following code listing shows the <code class="literal">SingleTestGenerator</code> interface:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> org.springframework.cloud.contract.verifier.builder
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.cloud.contract.verifier.file.ContractMetadata
<strong class="hl-tag" style="color: blue">/**
* Builds a single test.
*
* @since 1.1.0
*/</strong>
trait SingleTestGenerator {
<strong class="hl-tag" style="color: blue">/**
* Creates contents of a single test class in which all test scenarios from
* the contract metadata should be placed.
*
* @param properties - properties passed to the plugin
* @param listOfFiles - list of parsed contracts with additional metadata
* @param className - the name of the generated test class
* @param classPackage - the name of the package in which the test class should be stored
* @param includedDirectoryRelativePath - relative path to the included directory
* @return contents of a single test class
* @deprecated use{@link SingleTestGenerator#buildClass(ContractVerifierConfigProperties, Collection, String, GeneratedClassData)}
*/</strong>
<em><span class="hl-annotation" style="color: gray">@Deprecated</span></em>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">abstract</span> String buildClass(ContractVerifierConfigProperties properties,
Collection&lt;ContractMetadata&gt; listOfFiles, String className, String classPackage, String includedDirectoryRelativePath)
<strong class="hl-tag" style="color: blue">/**
* Creates contents of a single test class in which all test scenarios from
* the contract metadata should be placed.
*
* @param properties - properties passed to the plugin
* @param listOfFiles - list of parsed contracts with additional metadata
* @param generatedClassData - information about the generated class
* @param includedDirectoryRelativePath - relative path to the included directory
* @return contents of a single test class
*/</strong>
String buildClass(ContractVerifierConfigProperties properties,
Collection&lt;ContractMetadata&gt; listOfFiles, String includedDirectoryRelativePath, GeneratedClassData generatedClassData) {
String className = generatedClassData.className
String classPackage = generatedClassData.classPackage
String path = includedDirectoryRelativePath
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> buildClass(properties, listOfFiles, className, classPackage, path)
}
<strong class="hl-tag" style="color: blue">/**
* Extension that should be appended to the generated test class. E.g. {@code .java} or {@code .php}
*
* @param properties - properties passed to the plugin
*/</strong>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">abstract</span> String fileExtension(ContractVerifierConfigProperties properties)
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> GeneratedClassData {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String className
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String classPackage
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> java.nio.file.Path testClassPath
GeneratedClassData(String className, String classPackage,
java.nio.file.Path testClassPath) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.className = className
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.classPackage = classPackage
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.testClassPath = testClassPath
}
}
}</pre><p>Again, you must provide a <code class="literal">spring.factories</code> file, such as the one shown in the following
example:</p><pre class="screen">org.springframework.cloud.contract.verifier.builder.SingleTestGenerator=/
com.example.MyGenerator</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_using_the_custom_stub_generator" href="#_using_the_custom_stub_generator"></a>95.3&nbsp;Using the Custom Stub Generator</h2></div></div></div><p>If you want to generate stubs for stub servers other than WireMock, you can plug in your
own implementation of the <code class="literal">StubGenerator</code> interface. The following code listing shows the
<code class="literal">StubGenerator</code> interface:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> org.springframework.cloud.contract.verifier.converter
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> groovy.transform.CompileStatic
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.cloud.contract.spec.Contract
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.cloud.contract.verifier.file.ContractMetadata
<strong class="hl-tag" style="color: blue">/**
* Converts contracts into their stub representation.
*
* @since 1.1.0
*/</strong>
<em><span class="hl-annotation" style="color: gray">@CompileStatic</span></em>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> StubGenerator {
<strong class="hl-tag" style="color: blue">/**
* @return {@code true} if the converter can handle the file to convert it into a stub.
*/</strong>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> canHandleFileName(String fileName)
<strong class="hl-tag" style="color: blue">/**
* @return the collection of converted contracts into stubs. One contract can
* result in multiple stubs.
*/</strong>
Map&lt;Contract, String&gt; convertContents(String rootName, ContractMetadata content)
<strong class="hl-tag" style="color: blue">/**
* @return 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
* generated file name.
*
* Example: name of file with 2 contracts is {@code foo.groovy}, it will be
* converted by the implementation to {@code foo.json}. The recursive file
* converter will create two files {@code 0_foo.json} and {@code 1_foo.json}
*/</strong>
String generateOutputFileNameForInput(String inputFileName)
}</pre><p>Again, you must provide a <code class="literal">spring.factories</code> file, such as the one shown in the following
example:</p><pre class="screen"># Stub converters
org.springframework.cloud.contract.verifier.converter.StubGenerator=\
org.springframework.cloud.contract.verifier.wiremock.DslToWireMockClientConverter</pre><p>The default implementation is the WireMock stub generation.</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>You can provide multiple stub generator implementations. For example, from a single
DSL, you can produce both WireMock stubs and Pact files.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_using_the_custom_stub_runner" href="#_using_the_custom_stub_runner"></a>95.4&nbsp;Using the Custom Stub Runner</h2></div></div></div><p>If you decide to use a custom stub generation, you also need a custom way of running
stubs with your different stub provider.</p><p>Assume that you use <a class="link" href="https://github.com/dreamhead/moco" target="_top">Moco</a> to build your stubs and that
you have written a stub generator and placed your stubs in a JAR file.</p><p>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:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> org.springframework.cloud.contract.stubrunner.provider.moco
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> com.github.dreamhead.moco.bootstrap.arg.HttpArgs
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> com.github.dreamhead.moco.runner.JsonRunner
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> com.github.dreamhead.moco.runner.RunnerSetting
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> groovy.util.logging.Commons
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.cloud.contract.stubrunner.HttpServerStub
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.util.SocketUtils
<em><span class="hl-annotation" style="color: gray">@Commons</span></em>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MocoHttpServerStub <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">implements</span> HttpServerStub {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> started
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> JsonRunner runner
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">int</span> port
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">int</span> port() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (!isRunning()) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> -<span class="hl-number">1</span>
}
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> port
}
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> isRunning() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> started
}
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
HttpServerStub start() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> start(SocketUtils.findAvailableTcpPort())
}
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
HttpServerStub start(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">int</span> port) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.port = port
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>
}
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
HttpServerStub stop() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (!isRunning()) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>
}
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.runner.stop()
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>
}
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
HttpServerStub registerMappings(Collection&lt;File&gt; stubFiles) {
List&lt;RunnerSetting&gt; settings = stubFiles.findAll { it.name.endsWith(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"json"</span>) }
.collect {
log.info(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Trying to parse [${it.name}]"</span>)
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> RunnerSetting.aRunnerSetting().withStream(it.newInputStream()).
build()
}
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">catch</span> (Exception e) {
log.warn(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Exception occurred while trying to parse file [${it.name}]"</span>, e)
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> null
}
}.findAll { it }
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.runner = JsonRunner.newJsonRunnerWithSetting(settings,
HttpArgs.httpArgs().withPort(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.port).build())
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.runner.run()
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.started = true
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>
}
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
String registeredMappings() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">""</span>
}
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> isAccepted(File file) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> file.name.endsWith(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">".json"</span>)
}
}</pre><p>Then, you can register it in your <code class="literal">spring.factories</code> file, as shown in the following
example:</p><pre class="screen">org.springframework.cloud.contract.stubrunner.HttpServerStub=\
org.springframework.cloud.contract.stubrunner.provider.moco.MocoHttpServerStub</pre><p>Now you can run stubs with Moco.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>If you do not provide any implementation, then the default (WireMock)
implementation is used. If you provide more than one, the first one on the list is used.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_using_the_custom_stub_downloader" href="#_using_the_custom_stub_downloader"></a>95.5&nbsp;Using the Custom Stub Downloader</h2></div></div></div><p>You can customize the way your stubs are downloaded by creating an implementation of the
<code class="literal">StubDownloaderBuilder</code> interface, as shown in the following example:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> com.example;
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> CustomStubDownloaderBuilder <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">implements</span> StubDownloaderBuilder {
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> StubDownloader build(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> StubRunnerOptions stubRunnerOptions) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> StubDownloader() {
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Map.Entry&lt;StubConfiguration, File&gt; downloadAndUnpackStubJar(
StubConfiguration config) {
File unpackedStubs = retrieveStubs();
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> AbstractMap.SimpleEntry&lt;&gt;(
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> StubConfiguration(config.getGroupId(), config.getArtifactId(), version,
config.getClassifier()), unpackedStubs);
}
File retrieveStubs() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// here goes your custom logic to provide a folder where all the stubs reside</span>
}
}</pre><p>Then you can register it in your <code class="literal">spring.factories</code> file, as shown in the following
example:</p><pre class="screen"># Example of a custom Stub Downloader Provider
org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder=\
com.example.CustomStubDownloaderBuilder</pre><p>Now you can pick a folder with the source of your stubs.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>If you do not provide any implementation, then the default is used (scan classpath).
If you provide the <code class="literal">stubsMode = StubRunnerProperties.StubsMode.LOCAL</code> or
<code class="literal">, stubsMode = StubRunnerProperties.StubsMode.REMOTE</code> then the Aether implementation will be used
If you provide more than one, then the first one on the list is used.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="scm-stub-downloader" href="#scm-stub-downloader"></a>95.6&nbsp;Using the SCM Stub Downloader</h2></div></div></div><p>Whenever the <code class="literal">repositoryRoot</code> starts with a SCM protocol
(currently we support only <code class="literal">git://</code>), the stub downloader will try
to clone the repository and use it as a source of contracts
to generate tests or stubs.</p><p>Either via environment variables, system properties, properties set
inside the plugin or contracts repository configuration you can
tweak the downloader&#8217;s behaviour. Below you can find the list of
properties</p><div class="table"><a name="d0e28938" href="#d0e28938"></a><p class="title"><b>Table&nbsp;95.1.&nbsp;SCM Stub Downloader properties</b></p><div class="table-contents"><table class="table" summary="SCM Stub Downloader properties" style="border-collapse: collapse;border-top: 1px solid ; border-bottom: 1px solid ; "><colgroup><col class="col_1"><col class="col_2"><col class="col_3"></colgroup><tbody><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>Type of a property</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>Name of the property</p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Description</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>* <code class="literal">git.branch</code> (plugin prop)</p><p>* <code class="literal">stubrunner.properties.git.branch</code> (system prop)</p><p>* <code class="literal">STUBRUNNER_PROPERTIES_GIT_BRANCH</code> (env prop)</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>master</p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Which branch to checkout</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>* <code class="literal">git.username</code> (plugin prop)</p><p>* <code class="literal">stubrunner.properties.git.username</code> (system prop)</p><p>* <code class="literal">STUBRUNNER_PROPERTIES_GIT_USERNAME</code> (env prop)</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top">&nbsp;</td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Git clone username</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>* <code class="literal">git.password</code> (plugin prop)</p><p>* <code class="literal">stubrunner.properties.git.password</code> (system prop)</p><p>* <code class="literal">STUBRUNNER_PROPERTIES_GIT_PASSWORD</code> (env prop)</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top">&nbsp;</td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Git clone password</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>* <code class="literal">git.no-of-attempts</code> (plugin prop)</p><p>* <code class="literal">stubrunner.properties.git.no-of-attempts</code> (system prop)</p><p>* <code class="literal">STUBRUNNER_PROPERTIES_GIT_NO_OF_ATTEMPTS</code> (env prop)</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>10</p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Number of attempts to push the commits to <code class="literal">origin</code></p></td></tr><tr><td style="border-right: 1px solid ; " align="left" valign="top"><p>* <code class="literal">git.wait-between-attempts</code> (Plugin prop)</p><p>* <code class="literal">stubrunner.properties.git.wait-between-attempts</code> (system prop)</p><p>* <code class="literal">STUBRUNNER_PROPERTIES_GIT_WAIT_BETWEEN_ATTEMPTS</code> (env prop)</p></td><td style="border-right: 1px solid ; " align="left" valign="top"><p>1000</p></td><td style="" align="left" valign="top"><p>Number of millis to wait between attempts to push the commits to <code class="literal">origin</code></p></td></tr></tbody></table></div></div><br class="table-break"></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="pact-stub-downloader" href="#pact-stub-downloader"></a>95.7&nbsp;Using the Pact Stub Downloader</h2></div></div></div><p>Whenever the <code class="literal">repositoryRoot</code> starts with a Pact protocol
(starts with <code class="literal">pact://</code>), the stub downloader will try
to fetch the Pact contract definitions from the Pact Broker.
Whatever is set after <code class="literal">pact://</code> will be parsed as the Pact Broker URL.</p><p>Either via environment variables, system properties, properties set
inside the plugin or contracts repository configuration you can
tweak the downloader&#8217;s behaviour. Below you can find the list of
properties</p><div class="table"><a name="d0e29087" href="#d0e29087"></a><p class="title"><b>Table&nbsp;95.2.&nbsp;SCM Stub Downloader properties</b></p><div class="table-contents"><table class="table" summary="SCM Stub Downloader properties" style="border-collapse: collapse;border-top: 1px solid ; border-bottom: 1px solid ; "><colgroup><col class="col_1"><col class="col_2"><col class="col_3"></colgroup><tbody><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>Name of a property</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>Default</p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Description</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>* <code class="literal">pactbroker.host</code> (plugin prop)</p><p>* <code class="literal">stubrunner.properties.pactbroker.host</code> (system prop)</p><p>* <code class="literal">STUBRUNNER_PROPERTIES_PACTBROKER_HOST</code> (env prop)</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>Host from URL passed to <code class="literal">repositoryRoot</code></p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>What is the URL of Pact Broker</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>* <code class="literal">pactbroker.port</code> (plugin prop)</p><p>* <code class="literal">stubrunner.properties.pactbroker.port</code> (system prop)</p><p>* <code class="literal">STUBRUNNER_PROPERTIES_PACTBROKER_PORT</code> (env prop)</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>Port from URL passed to <code class="literal">repositoryRoot</code></p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>What is the port of Pact Broker</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>* <code class="literal">pactbroker.protocol</code> (plugin prop)</p><p>* <code class="literal">stubrunner.properties.pactbroker.protocol</code> (system prop)</p><p>* <code class="literal">STUBRUNNER_PROPERTIES_PACTBROKER_PROTOCOL</code> (env prop)</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>Protocol from URL passed to <code class="literal">repositoryRoot</code></p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>What is the protocol of Pact Broker</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>* <code class="literal">pactbroker.tags</code> (plugin prop)</p><p>* <code class="literal">stubrunner.properties.pactbroker.tags</code> (system prop)</p><p>* <code class="literal">STUBRUNNER_PROPERTIES_PACTBROKER_TAGS</code> (env prop)</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>Version of the stub, or <code class="literal">latest</code> if version is <code class="literal">+</code></p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>What tags should be used to fetch the stub</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>* <code class="literal">pactbroker.auth.scheme</code> (plugin prop)</p><p>* <code class="literal">stubrunner.properties.pactbroker.auth.scheme</code> (system prop)</p><p>* <code class="literal">STUBRUNNER_PROPERTIES_PACTBROKER_AUTH_SCHEME</code> (env prop)</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">Basic</code></p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>What kind of authentication should be used to connect to the Pact Broker</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>* <code class="literal">pactbroker.auth.username</code> (plugin prop)</p><p>* <code class="literal">stubrunner.properties.pactbroker.auth.username</code> (system prop)</p><p>* <code class="literal">STUBRUNNER_PROPERTIES_PACTBROKER_AUTH_USERNAME</code> (env prop)</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>The username passed to <code class="literal">contractsRepositoryUsername</code> (maven) or <code class="literal">contractRepository.username</code> (gradle)</p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Username used to connect to the Pact Broker</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>* <code class="literal">pactbroker.auth.password</code> (plugin prop)</p><p>* <code class="literal">stubrunner.properties.pactbroker.auth.password</code> (system prop)</p><p>* <code class="literal">STUBRUNNER_PROPERTIES_PACTBROKER_AUTH_PASSWORD</code> (env prop)</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>The password passed to <code class="literal">contractsRepositoryPassword</code> (maven) or <code class="literal">contractRepository.password</code> (gradle)</p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Password used to connect to the Pact Broker</p></td></tr><tr><td style="border-right: 1px solid ; " align="left" valign="top"><p>* <code class="literal">pactbroker.provider-name-with-group-id</code> (plugin prop)</p><p>* <code class="literal">stubrunner.properties.pactbroker.provider-name-with-group-id</code> (system prop)</p><p>* <code class="literal">STUBRUNNER_PROPERTIES_PACTBROKER_PROVIDER_NAME_WITH_GROUP_ID</code> (env prop)</p></td><td style="border-right: 1px solid ; " align="left" valign="top"><p>false</p></td><td style="" align="left" valign="top"><p>When <code class="literal">true</code>, the provider name will be a combination of <code class="literal">groupId:artifactId</code>. If <code class="literal">false</code>, just <code class="literal">artifactId</code> is used</p></td></tr></tbody></table></div></div><br class="table-break"></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__customization.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_contract.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="multi__spring_cloud_contract_wiremock.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">94.&nbsp;Customization&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;96.&nbsp;Spring Cloud Contract WireMock</td></tr></table></div></body></html>