431 lines
17 KiB
HTML
431 lines
17 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="generator" content="Asciidoctor 1.5.7.1">
|
|
<title>Spring Cloud Contract Stub Runner</title>
|
|
<link rel="stylesheet" href="css/spring.css">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
|
|
|
<style>
|
|
.hidden {
|
|
display: none;
|
|
}
|
|
|
|
.switch {
|
|
border-width: 1px 1px 0 1px;
|
|
border-style: solid;
|
|
border-color: #7a2518;
|
|
display: inline-block;
|
|
}
|
|
|
|
.switch--item {
|
|
padding: 10px;
|
|
background-color: #ffffff;
|
|
color: #7a2518;
|
|
display: inline-block;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.switch--item:not(:first-child) {
|
|
border-width: 0 0 0 1px;
|
|
border-style: solid;
|
|
border-color: #7a2518;
|
|
}
|
|
|
|
.switch--item.selected {
|
|
background-color: #7a2519;
|
|
color: #ffffff;
|
|
}
|
|
</style>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/zepto/1.2.0/zepto.min.js"></script>
|
|
<script type="text/javascript">
|
|
function addBlockSwitches() {
|
|
$('.primary').each(function() {
|
|
primary = $(this);
|
|
createSwitchItem(primary, createBlockSwitch(primary)).item.addClass("selected");
|
|
primary.children('.title').remove();
|
|
});
|
|
$('.secondary').each(function(idx, node) {
|
|
secondary = $(node);
|
|
primary = findPrimary(secondary);
|
|
switchItem = createSwitchItem(secondary, primary.children('.switch'));
|
|
switchItem.content.addClass('hidden');
|
|
findPrimary(secondary).append(switchItem.content);
|
|
secondary.remove();
|
|
});
|
|
}
|
|
|
|
function createBlockSwitch(primary) {
|
|
blockSwitch = $('<div class="switch"></div>');
|
|
primary.prepend(blockSwitch);
|
|
return blockSwitch;
|
|
}
|
|
|
|
function findPrimary(secondary) {
|
|
candidate = secondary.prev();
|
|
while (!candidate.is('.primary')) {
|
|
candidate = candidate.prev();
|
|
}
|
|
return candidate;
|
|
}
|
|
|
|
function createSwitchItem(block, blockSwitch) {
|
|
blockName = block.children('.title').text();
|
|
content = block.children('.content').first().append(block.next('.colist'));
|
|
item = $('<div class="switch--item">' + blockName + '</div>');
|
|
item.on('click', '', content, function(e) {
|
|
$(this).addClass('selected');
|
|
$(this).siblings().removeClass('selected');
|
|
e.data.siblings('.content').addClass('hidden');
|
|
e.data.removeClass('hidden');
|
|
});
|
|
blockSwitch.append(item);
|
|
return {'item': item, 'content': content};
|
|
}
|
|
|
|
$(addBlockSwitches);
|
|
</script>
|
|
|
|
</head>
|
|
<body class="book toc2 toc-left">
|
|
<div id="header">
|
|
<div id="toc" class="toc2">
|
|
<div id="toctitle">Table of Contents</div>
|
|
<ul class="sectlevel1">
|
|
<li><a href="#_spring_cloud_contract_stub_runner">Spring Cloud Contract Stub Runner</a>
|
|
<ul class="sectlevel2">
|
|
<li><a href="#_snapshot_versions">Snapshot versions</a></li>
|
|
<li><a href="#publishing-stubs-as-jars">Publishing Stubs as JARs</a></li>
|
|
<li><a href="#_common">Common</a></li>
|
|
<li><a href="#stubrunner-docker">Stub Runner Docker</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div id="content">
|
|
<div class="sect1">
|
|
<h2 id="_spring_cloud_contract_stub_runner"><a class="link" href="#_spring_cloud_contract_stub_runner">Spring Cloud Contract Stub Runner</a></h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>One of the issues that you might encounter while using Spring Cloud Contract Verifier is
|
|
passing the generated WireMock JSON stubs from the server side to the client side (or to
|
|
various clients). The same takes place in terms of client-side generation for messaging.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Copying the JSON files and setting the client side for messaging manually is out of the
|
|
question. That is why we introduced Spring Cloud Contract Stub Runner. It can
|
|
automatically download and run the stubs for you.</p>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="_snapshot_versions"><a class="link" href="#_snapshot_versions">Snapshot versions</a></h3>
|
|
<div class="paragraph">
|
|
<p>Add the additional snapshot repository to your <code>build.gradle</code> file to use snapshot
|
|
versions, which are automatically uploaded after every successful build:</p>
|
|
</div>
|
|
<div class="listingblock primary">
|
|
<div class="title">Maven</div>
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="listingblock secondary">
|
|
<div class="title">Gradle</div>
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="publishing-stubs-as-jars"><a class="link" href="#publishing-stubs-as-jars">Publishing Stubs as JARs</a></h3>
|
|
<div class="paragraph">
|
|
<p>The easiest approach would be to centralize the way stubs are kept. For example, you can
|
|
keep them as jars in a Maven repository.</p>
|
|
</div>
|
|
<div class="admonitionblock tip">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-tip" title="Tip"></i>
|
|
</td>
|
|
<td class="content">
|
|
For both Maven and Gradle, the setup comes ready to work. However, you can customize
|
|
it if you want to.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="listingblock primary">
|
|
<div class="title">Maven</div>
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"><!-- First disable the default jar setup in the properties section -->
|
|
|
|
<!-- Next add the assembly plugin to your build -->
|
|
|
|
<!-- Finally setup your assembly. Below you can find the contents of src/main/assembly/stub.xml --></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="listingblock secondary">
|
|
<div class="title">Gradle</div>
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="_common"><a class="link" href="#_common">Common</a></h3>
|
|
<div class="paragraph">
|
|
<p>This section briefly describes common properties, including:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><a href="#common-properties-junit-spring">Common Properties for JUnit and Spring</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#stub-runner-stub-ids">Stub Runner Stubs IDs</a></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="common-properties-junit-spring"><a class="link" href="#common-properties-junit-spring">Common Properties for JUnit and Spring</a></h4>
|
|
<div class="paragraph">
|
|
<p>You can set repetitive properties by using system properties or Spring configuration
|
|
properties. Here are their names with their default values:</p>
|
|
</div>
|
|
<table class="tableblock frame-topbot grid-all stretch">
|
|
<colgroup>
|
|
<col style="width: 33.3333%;">
|
|
<col style="width: 33.3333%;">
|
|
<col style="width: 33.3334%;">
|
|
</colgroup>
|
|
<thead>
|
|
<tr>
|
|
<th class="tableblock halign-left valign-top">Property name</th>
|
|
<th class="tableblock halign-left valign-top">Default value</th>
|
|
<th class="tableblock halign-left valign-top">Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.minPort</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">10000</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Minimum value of a port for a started WireMock with stubs.</p></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.maxPort</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">15000</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Maximum value of a port for a started WireMock with stubs.</p></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.repositoryRoot</p></td>
|
|
<td class="tableblock halign-left valign-top"></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Maven repo URL. If blank, then call the local maven repo.</p></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.classifier</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">stubs</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Default classifier for the stub artifacts.</p></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.stubsMode</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">CLASSPATH</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">The way you want to fetch and register the stubs</p></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.ids</p></td>
|
|
<td class="tableblock halign-left valign-top"></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Array of Ivy notation stubs to download.</p></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.username</p></td>
|
|
<td class="tableblock halign-left valign-top"></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional username to access the tool that stores the JARs with
|
|
stubs.</p></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.password</p></td>
|
|
<td class="tableblock halign-left valign-top"></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional password to access the tool that stores the JARs with
|
|
stubs.</p></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.stubsPerConsumer</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Set to <code>true</code> if you want to use different stubs for
|
|
each consumer instead of registering all stubs for every consumer.</p></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.consumerName</p></td>
|
|
<td class="tableblock halign-left valign-top"></td>
|
|
<td class="tableblock halign-left valign-top"><p class="tableblock">If you want to use a stub for each consumer and want to
|
|
override the consumer name just change this value.</p></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="stub-runner-stub-ids"><a class="link" href="#stub-runner-stub-ids">Stub Runner Stubs IDs</a></h4>
|
|
<div class="paragraph">
|
|
<p>You can provide the stubs to download via the <code>stubrunner.ids</code> system property. They
|
|
follow this pattern:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">groupId:artifactId:version:classifier:port</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Note that <code>version</code>, <code>classifier</code> and <code>port</code> are optional.</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>If you do not provide the <code>port</code>, a random one will be picked.</p>
|
|
</li>
|
|
<li>
|
|
<p>If you do not provide the <code>classifier</code>, the default is used. (Note that you can
|
|
pass an empty classifier this way: <code>groupId:artifactId:version:</code>).</p>
|
|
</li>
|
|
<li>
|
|
<p>If you do not provide the <code>version</code>, then the <code>+</code> will be passed and the latest one is
|
|
downloaded.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p><code>port</code> means the port of the WireMock server.</p>
|
|
</div>
|
|
<div class="admonitionblock important">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-important" title="Important"></i>
|
|
</td>
|
|
<td class="content">
|
|
Starting with version 1.0.4, you can provide a range of versions that you
|
|
would like the Stub Runner to take into consideration. You can read more about the
|
|
<a href="https://wiki.eclipse.org/Aether/New_and_Noteworthy#Version_Ranges">Aether versioning
|
|
ranges here</a>.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="stubrunner-docker"><a class="link" href="#stubrunner-docker">Stub Runner Docker</a></h3>
|
|
<div class="paragraph">
|
|
<p>We’re publishing a <code>spring-cloud/spring-cloud-contract-stub-runner</code> Docker image
|
|
that will start the standalone version of Stub Runner.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>If you want to learn more about the basics of Maven, artifact ids,
|
|
group ids, classifiers and Artifact Managers, just click here <a href="#docker-project">[docker-project]</a>.</p>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="_how_to_use_it"><a class="link" href="#_how_to_use_it">How to use it</a></h4>
|
|
<div class="paragraph">
|
|
<p>Just execute the docker image. You can pass any of the <a href="#common-properties-junit-spring">Common Properties for JUnit and Spring</a>
|
|
as environment variables. The convention is that all the
|
|
letters should be upper case. The camel case notation should
|
|
and the dot (<code>.</code>) should be separated via underscore (<code>_</code>). E.g.
|
|
the <code>stubrunner.repositoryRoot</code> property should be represented
|
|
as a <code>STUBRUNNER_REPOSITORY_ROOT</code> environment variable.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="_example_of_client_side_usage_in_a_non_jvm_project"><a class="link" href="#_example_of_client_side_usage_in_a_non_jvm_project">Example of client side usage in a non JVM project</a></h4>
|
|
<div class="paragraph">
|
|
<p>We’d like to use the stubs created in this <a href="#docker-server-side">[docker-server-side]</a> step.
|
|
Let’s assume that we want to run the stubs on port <code>9876</code>. The NodeJS code
|
|
is available here:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ git clone https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs
|
|
$ cd bookstore</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Let’s run the Stub Runner Boot application with the stubs.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash"># Provide the Spring Cloud Contract Docker version
|
|
$ SC_CONTRACT_DOCKER_VERSION="..."
|
|
# The IP at which the app is running and Docker container can reach it
|
|
$ APP_IP="192.168.0.100"
|
|
# Spring Cloud Contract Stub Runner properties
|
|
$ STUBRUNNER_PORT="8083"
|
|
# Stub coordinates 'groupId:artifactId:version:classifier:port'
|
|
$ STUBRUNNER_IDS="com.example:bookstore:0.0.1.RELEASE:stubs:9876"
|
|
$ STUBRUNNER_REPOSITORY_ROOT="http://${APP_IP}:8081/artifactory/libs-release-local"
|
|
# Run the docker with Stub Runner Boot
|
|
$ docker run --rm -e "STUBRUNNER_IDS=${STUBRUNNER_IDS}" -e "STUBRUNNER_REPOSITORY_ROOT=${STUBRUNNER_REPOSITORY_ROOT}" -e "STUBRUNNER_STUBS_MODE=REMOTE" -p "${STUBRUNNER_PORT}:${STUBRUNNER_PORT}" -p "9876:9876" springcloud/spring-cloud-contract-stub-runner:"${SC_CONTRACT_DOCKER_VERSION}"</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>What’s happening is that</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>a standalone Stub Runner application got started</p>
|
|
</li>
|
|
<li>
|
|
<p>it downloaded the stub with coordinates <code>com.example:bookstore:0.0.1.RELEASE:stubs</code> on port <code>9876</code></p>
|
|
</li>
|
|
<li>
|
|
<p>it got downloaded from Artifactory running at <code><a href="http://192.168.0.100:8081/artifactory/libs-release-local" class="bare">http://192.168.0.100:8081/artifactory/libs-release-local</a></code></p>
|
|
</li>
|
|
<li>
|
|
<p>after a while Stub Runner will be running on port <code>8083</code></p>
|
|
</li>
|
|
<li>
|
|
<p>and the stubs will be running at port <code>9876</code></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>On the server side we built a stateful stub. Let’s use curl to assert
|
|
that the stubs are setup properly.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash"># let's execute the first request (no response is returned)
|
|
$ curl -H "Content-Type:application/json" -X POST --data '{ "title" : "Title", "genre" : "Genre", "description" : "Description", "author" : "Author", "publisher" : "Publisher", "pages" : 100, "image_url" : "https://d213dhlpdb53mu.cloudfront.net/assets/pivotal-square-logo-41418bd391196c3022f3cd9f3959b3f6d7764c47873d858583384e759c7db435.svg", "buy_url" : "https://pivotal.io" }' http://localhost:9876/api/books
|
|
# Now time for the second request
|
|
$ curl -X GET http://localhost:9876/api/books
|
|
# You will receive contents of the JSON</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="admonitionblock important">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-important" title="Important"></i>
|
|
</td>
|
|
<td class="content">
|
|
If you want use the stubs that you have built locally, on your host,
|
|
then you should pass the environment variable <code>-e STUBRUNNER_STUBS_MODE=LOCAL</code> and mount
|
|
the volume of your local m2 <code>-v "${HOME}/.m2/:/root/.m2:ro"</code>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script type="text/javascript" src="js/tocbot/tocbot.min.js"></script>
|
|
<script type="text/javascript" src="js/toc.js"></script>
|
|
<link rel="stylesheet" href="js/highlight/styles/atom-one-dark-reasonable.min.css">
|
|
<script src="js/highlight/highlight.min.js"></script>
|
|
<script>hljs.initHighlighting()</script>
|
|
</body>
|
|
</html> |