Sync docs from master to gh-pages

This commit is contained in:
buildmaster
2017-04-27 15:29:32 +00:00
parent 41769b4daa
commit d68b1aa023

View File

@@ -638,6 +638,12 @@ $(addBlockSwitches);
</li>
<li><a href="#_stub_runner_core">Stub Runner Core</a>
<ul class="sectlevel3">
<li><a href="#_retrieving_stubs">Retrieving stubs</a>
<ul class="sectlevel4">
<li><a href="#_stub_downloading">Stub downloading</a></li>
<li><a href="#_classpath_scanning">Classpath scanning</a></li>
</ul>
</li>
<li><a href="#_running_stubs">Running stubs</a>
<ul class="sectlevel4">
<li><a href="#_limitations">Limitations</a></li>
@@ -4225,10 +4231,195 @@ publishing {
<a href="http://martinfowler.com/articles/consumerDrivenContracts.html">Consumer Driven Contracts</a>.</p>
</div>
<div class="paragraph">
<p>Stub Runner allows you to automatically download the stubs of the provided dependencies, start WireMock servers for them and feed them with proper stub definitions.
<p>Stub Runner allows you to automatically download the stubs of the provided dependencies (or pick those from the classpath), start WireMock servers for them and feed them with proper stub definitions.
For messaging, special stub routes are defined.</p>
</div>
<div class="sect3">
<h4 id="_retrieving_stubs">Retrieving stubs</h4>
<div class="paragraph">
<p>You can pick the following options of acquiring stubs</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Aether based solution that downloads JARs with stubs from Artifactory / Nexus</p>
</li>
<li>
<p>Classpath scanning solution that searches classpath via pattern to retrieve stubs</p>
</li>
<li>
<p>Write your own implementation of the <code>org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder</code> for full customization</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The latter example is described in the <a href="#custom_stub_runner">Custom Stub Runner</a> section.</p>
</div>
<div class="sect4">
<h5 id="_stub_downloading">Stub downloading</h5>
<div class="paragraph">
<p>If you provide the <code>stubrunner.repositoryRoot</code> or <code>stubrunner.workOffline</code> flag will be set
to <code>true</code> then Stub Runner will connect to the given server and download the required jars.
It will then unpack the JAR to a temporary folder and reference those files in further
contract processing.</p>
</div>
<div class="paragraph">
<p>Example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">@AutoConfigureStubRunner(repositoryRoot="http://foo.bar", ids = "com.example:beer-api-producer:+:stubs:8095")</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="_classpath_scanning">Classpath scanning</h5>
<div class="paragraph">
<p>If you <strong>DON&#8217;T</strong> provide the <code>stubrunner.repositoryRoot</code> or <code>stubrunner.workOffline</code> flag will
be set to <code>false</code> (that&#8217;s the default) then classpath will get scanned. Let&#8217;s look at the
following example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">@AutoConfigureStubRunner(ids = {
"com.example:beer-api-producer:+:stubs:8095",
"com.example.foo:bar:1.0.0:superstubs:8096"
})</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you&#8217;ve added the dependencies to your classpath</p>
</div>
<div class="listingblock primary">
<div class="title">Maven</div>
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;dependency&gt;
&lt;groupId&gt;com.example&lt;/groupId&gt;
&lt;artifactId&gt;beer-api-producer-restdocs&lt;/artifactId&gt;
&lt;classifier&gt;stubs&lt;/classifier&gt;
&lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;exclusions&gt;
&lt;exclusion&gt;
&lt;groupId&gt;*&lt;/groupId&gt;
&lt;artifactId&gt;*&lt;/artifactId&gt;
&lt;/exclusion&gt;
&lt;/exclusions&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;com.example.foo&lt;/groupId&gt;
&lt;artifactId&gt;bar&lt;/artifactId&gt;
&lt;classifier&gt;superstubs&lt;/classifier&gt;
&lt;version&gt;1.0.0&lt;/version&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;exclusions&gt;
&lt;exclusion&gt;
&lt;groupId&gt;*&lt;/groupId&gt;
&lt;artifactId&gt;*&lt;/artifactId&gt;
&lt;/exclusion&gt;
&lt;/exclusions&gt;
&lt;/dependency&gt;</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Gradle</div>
<div class="content">
<pre class="highlight"><code class="language-groovy" data-lang="groovy">testCompile("com.example:beer-api-producer-restdocs:0.0.1-SNAPSHOT:stubs") {
transitive = false
}
testCompile("com.example.foo:bar:1.0.0:superstubs") {
transitive = false
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Then the following locations on your classpath will get scanned. For <code>com.example:beer-api-producer-restdocs</code></p>
</div>
<div class="ulist">
<ul>
<li>
<p>/META-INF/com.example/beer-api-producer-restdocs/<strong>*/</strong>.*</p>
</li>
<li>
<p>/contracts/com.example/beer-api-producer-restdocs/<strong>*/</strong>.*</p>
</li>
<li>
<p>/mappings/com.example/beer-api-producer-restdocs/<strong>*/</strong>.*</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>and <code>com.example.foo:bar</code></p>
</div>
<div class="ulist">
<ul>
<li>
<p>/META-INF/com.example.foo/bar/<strong>*/</strong>.*</p>
</li>
<li>
<p>/contracts/com.example.foo/bar/<strong>*/</strong>.*</p>
</li>
<li>
<p>/mappings/com.example.foo/bar/<strong>*/</strong>.*</p>
</li>
</ul>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">Tip</div>
</td>
<td class="content">
As you can see you have to explicitly provide the group and artifact ids when packaging the
producer stubs.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The producer would setup the contracts like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">└── src
└── test
└── resources
└── contracts
   └── com.example
      └── beer-api-producer-restdocs
      └── nested
      └── contract3.groovy</code></pre>
</div>
</div>
<div class="paragraph">
<p>To achieve proper stub packaging.</p>
</div>
<div class="paragraph">
<p>Or using the <a href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/blob/master/producer_with_restdocs/pom.xml">Maven <code>assembly</code> plugin</a> or
<a href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/blob/master/producer_with_restdocs/build.gradle">Gradle Jar</a> task you have to create the following
structure in your stubs jar.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">└── META-INF
└── com.example
└── beer-api-producer-restdocs
└── 2.0.0
├── contracts
│   └── nested
   │ └── contract2.groovy
   └── mappings
   └── mapping.json</code></pre>
</div>
</div>
<div class="paragraph">
<p>By maintaining this structure classpath gets scanned and you can profit from the messaging /
HTTP stubs without the need to download artifacts.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_running_stubs">Running stubs</h4>
<div class="sect4">
<h5 id="_limitations">Limitations</h5>
@@ -8603,8 +8794,7 @@ class MocoHttpServerStub implements HttpServerStub {
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code># Example of a custom HTTP Server Stub
org.springframework.cloud.contract.stubrunner.HttpServerStub=\
<pre class="highlight"><code>org.springframework.cloud.contract.stubrunner.HttpServerStub=\
org.springframework.cloud.contract.stubrunner.provider.moco.MocoHttpServerStub</code></pre>
</div>
</div>
@@ -8628,93 +8818,30 @@ will be picked. If you provide more than one then the first one on the list will
<div class="sect3">
<h4 id="_custom_stub_downloader">Custom Stub Downloader</h4>
<div class="paragraph">
<p>You can customize the way your stubs are downloaded. If you don&#8217;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 <code>json</code> 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.</p>
<p>You can customize the way your stubs are downloaded. It&#8217;s enough to create an
implementation of the <code>StubDownloaderBuilder</code></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">package org.springframework.cloud.contract.stubrunner.provider.moco
<pre class="highlight"><code class="language-java" data-lang="java">package com.example;
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
* love and attention to go to the main sources.
*
* @author Marcin Grzejszczak
*/
class ClasspathStubProvider implements StubDownloaderBuilder {
private static final int TEMP_DIR_ATTEMPTS = 10000
class CustomStubDownloaderBuilder implements StubDownloaderBuilder {
@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 -&gt;
Files.copy(resource.getInputStream(), new File(tmp, resource.getFile().getName()).toPath())
public StubDownloader build(final StubRunnerOptions stubRunnerOptions) {
return new StubDownloader() {
@Override
public Map.Entry&lt;StubConfiguration, File&gt; downloadAndUnpackStubJar(
StubConfiguration config) {
File unpackedStubs = retrieveStubs();
return new AbstractMap.SimpleEntry&lt;&gt;(
new StubConfiguration(config.getGroupId(), config.getArtifactId(), version,
config.getClassifier()), unpackedStubs);
}
return new StubDownloader() {
@Override
public Map.Entry&lt;StubConfiguration, File&gt; downloadAndUnpackStubJar(
StubConfiguration stubConfiguration) {
return new AbstractMap.SimpleEntry(configuration, tmp)
}
File retrieveStubs() {
// here goes your custom logic to provide a folder where all the stubs reside
}
} catch (IOException e) {
throw new IllegalStateException(e)
}
}
private String repoRoot(StubRunnerOptions stubRunnerOptions) {
switch (stubRunnerOptions.stubRepositoryRoot) {
case { !it }:
return ""
case { String root -&gt; 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 File createTempDir() {
File baseDir = new File(System.getProperty("java.io.tmpdir"))
String baseName = System.currentTimeMillis() + "-"
for (int counter = 0; counter &lt; TEMP_DIR_ATTEMPTS; counter++) {
File tempDir = new File(baseDir, baseName + counter)
if (tempDir.mkdir()) {
return tempDir
}
}
throw new IllegalStateException(
"Failed to create directory within " + TEMP_DIR_ATTEMPTS + " attempts (tried " + baseName + "0 to " + baseName + (
TEMP_DIR_ATTEMPTS - 1) + ")")
}
}</code></pre>
</div>
</div>
@@ -8725,7 +8852,7 @@ class ClasspathStubProvider implements StubDownloaderBuilder {
<div class="content">
<pre class="highlight"><code># Example of a custom Stub Downloader Provider
org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder=\
org.springframework.cloud.contract.stubrunner.provider.moco.ClasspathStubProvider</code></pre>
com.example.CustomStubDownloaderBuilder</code></pre>
</div>
</div>
<div class="paragraph">
@@ -8738,8 +8865,11 @@ org.springframework.cloud.contract.stubrunner.provider.moco.ClasspathStubProvide
<div class="title">Important</div>
</td>
<td class="content">
If you don&#8217;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.
If you don&#8217;t provide any implementation then the default one will be picked.
If you provide <code>repositoryRoot</code> property or <code>workOffline</code> flag then Aether based
that will download stubs from a remote repo will be picked. If you don&#8217;t provide these
values then the <code>ClasspathStubProvider</code> will be picked that will scan the classpath.
If you provide more than one, then the first one on the list will be picked.
</td>
</tr>
</table>