Redirects to contract project website
This commit is contained in:
committed by
GitHub
parent
dd9d263f83
commit
7126694f51
@@ -1,680 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<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.8">
|
||||
<title>Spring Cloud Contract</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};
|
||||
}
|
||||
|
||||
function globalSwitch() {
|
||||
$('.switch--item').each(function() {
|
||||
$(this).off('click');
|
||||
$(this).on('click', function() {
|
||||
selectedText = $(this).text()
|
||||
selectedIndex = $(this).index()
|
||||
$(".switch--item").filter(function() { return ($(this).text() === selectedText) }).each(function() {
|
||||
$(this).addClass('selected');
|
||||
$(this).siblings().removeClass('selected');
|
||||
selectedContent = $(this).parent().siblings(".content").eq(selectedIndex)
|
||||
selectedContent.removeClass('hidden');
|
||||
selectedContent.siblings().addClass('hidden');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(addBlockSwitches);
|
||||
$(globalSwitch);
|
||||
<meta http-equiv="refresh" content="1; url=https://spring.io/projects/spring-cloud-contract#learn">
|
||||
|
||||
<script>
|
||||
window.location.href = "https://spring.io/projects/spring-cloud-contract#learn"
|
||||
</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">Spring Cloud Contract</a>
|
||||
<ul class="sectlevel2">
|
||||
<li><a href="#_spring_cloud_contract_workshops">Spring Cloud Contract workshops</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#_project_page">Project page</a></li>
|
||||
<li><a href="#_contributing">Contributing</a>
|
||||
<ul class="sectlevel2">
|
||||
<li><a href="#_sign_the_contributor_license_agreement">Sign the Contributor License Agreement</a></li>
|
||||
<li><a href="#_code_of_conduct">Code of Conduct</a></li>
|
||||
<li><a href="#_code_conventions_and_housekeeping">Code Conventions and Housekeeping</a></li>
|
||||
<li><a href="#_checkstyle">Checkstyle</a></li>
|
||||
<li><a href="#_ide_setup">IDE setup</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#_how_to_build_spring_cloud_contract">How to Build Spring Cloud Contract</a>
|
||||
<ul class="sectlevel2">
|
||||
<li><a href="#_project_structure">Project structure</a></li>
|
||||
<li><a href="#_commands">Commands</a></li>
|
||||
<li><a href="#_helpful_scripts">Helpful scripts</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div class="sect1">
|
||||
<h2 id="_spring_cloud_contract"><a class="link" href="#_spring_cloud_contract">Spring Cloud Contract</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>You always need confidence when pushing new features into a new application or service in
|
||||
a distributed system. To that end, this project provides support for consumer-driven
|
||||
contracts and service schemas in Spring applications, covering a range of options for
|
||||
writing tests, publishing them as assets, and asserting that a contract is kept by
|
||||
producers and consumers — for both HTTP and message-based interactions.</p>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_spring_cloud_contract_workshops"><a class="link" href="#_spring_cloud_contract_workshops">Spring Cloud Contract workshops</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>If you prefer to learn about the project by doing some tutorials, you can check out the
|
||||
workshops under
|
||||
<a href="https://cloud-samples.spring.io/spring-cloud-contract-samples/workshops.html">this link</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="_project_page"><a class="link" href="#_project_page">Project page</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>You can read more about Spring Cloud Contract by going to <a href="https://spring.io/projects/spring-cloud-contract">the project page</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="_contributing"><a class="link" href="#_contributing">Contributing</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>Spring Cloud is released under the non-restrictive Apache 2.0 license,
|
||||
and follows a very standard Github development process, using Github
|
||||
tracker for issues and merging pull requests into master. If you want
|
||||
to contribute even something trivial please do not hesitate, but
|
||||
follow the guidelines below.</p>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_sign_the_contributor_license_agreement"><a class="link" href="#_sign_the_contributor_license_agreement">Sign the Contributor License Agreement</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>Before we accept a non-trivial patch or pull request we will need you to sign the
|
||||
<a href="https://cla.pivotal.io/sign/spring">Contributor License Agreement</a>.
|
||||
Signing the contributor’s agreement does not grant anyone commit rights to the main
|
||||
repository, but it does mean that we can accept your contributions, and you will get an
|
||||
author credit if we do. Active contributors might be asked to join the core team, and
|
||||
given the ability to merge pull requests.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_code_of_conduct"><a class="link" href="#_code_of_conduct">Code of Conduct</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>This project adheres to the Contributor Covenant <a href="https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc">code of
|
||||
conduct</a>. By participating, you are expected to uphold this code. Please report
|
||||
unacceptable behavior to <a href="mailto:spring-code-of-conduct@pivotal.io">spring-code-of-conduct@pivotal.io</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_code_conventions_and_housekeeping"><a class="link" href="#_code_conventions_and_housekeeping">Code Conventions and Housekeeping</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>None of these is essential for a pull request, but they will all help. They can also be
|
||||
added after the original pull request but before a merge.</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>Use the Spring Framework code format conventions. If you use Eclipse
|
||||
you can import formatter settings using the
|
||||
<code>eclipse-code-formatter.xml</code> file from the
|
||||
<a href="https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-dependencies-parent/eclipse-code-formatter.xml">Spring
|
||||
Cloud Build</a> project. If using IntelliJ, you can use the
|
||||
<a href="https://plugins.jetbrains.com/plugin/6546">Eclipse Code Formatter
|
||||
Plugin</a> to import the same file.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Make sure all new <code>.java</code> files to have a simple Javadoc class comment with at least an
|
||||
<code>@author</code> tag identifying you, and preferably at least a paragraph on what the class is
|
||||
for.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Add the ASF license header comment to all new <code>.java</code> files (copy from existing files
|
||||
in the project)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Add yourself as an <code>@author</code> to the .java files that you modify substantially (more
|
||||
than cosmetic changes).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Add some Javadocs and, if you change the namespace, some XSD doc elements.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>A few unit tests would help a lot as well — someone has to do it.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If no-one else is using your branch, please rebase it against the current master (or
|
||||
other target branch in the main project).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>When writing a commit message please follow <a href="https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html">these conventions</a>,
|
||||
if you are fixing an existing issue please add <code>Fixes gh-XXXX</code> at the end of the commit
|
||||
message (where XXXX is the issue number).</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_checkstyle"><a class="link" href="#_checkstyle">Checkstyle</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>Spring Cloud Build comes with a set of checkstyle rules. You can find them in the <code>spring-cloud-build-tools</code> module. The most notable files under the module are:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="title">spring-cloud-build-tools/</div>
|
||||
<div class="content">
|
||||
<pre>└── src
|
||||
├── checkstyle
|
||||
│ └── checkstyle-suppressions.xml <i class="conum" data-value="3"></i><b>(3)</b>
|
||||
└── main
|
||||
└── resources
|
||||
├── checkstyle-header.txt <i class="conum" data-value="2"></i><b>(2)</b>
|
||||
└── checkstyle.xml <i class="conum" data-value="1"></i><b>(1)</b></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colist arabic">
|
||||
<table>
|
||||
<tr>
|
||||
<td><i class="conum" data-value="1"></i><b>1</b></td>
|
||||
<td>Default Checkstyle rules</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="conum" data-value="2"></i><b>2</b></td>
|
||||
<td>File header setup</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="conum" data-value="3"></i><b>3</b></td>
|
||||
<td>Default suppression rules</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="_checkstyle_configuration"><a class="link" href="#_checkstyle_configuration">Checkstyle configuration</a></h4>
|
||||
<div class="paragraph">
|
||||
<p>Checkstyle rules are <strong>disabled by default</strong>. To add checkstyle to your project just define the following properties and plugins.</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="title">pom.xml</div>
|
||||
<div class="content">
|
||||
<pre><properties>
|
||||
<maven-checkstyle-plugin.failsOnError>true</maven-checkstyle-plugin.failsOnError> <i class="conum" data-value="1"></i><b>(1)</b>
|
||||
<maven-checkstyle-plugin.failsOnViolation>true
|
||||
</maven-checkstyle-plugin.failsOnViolation> <i class="conum" data-value="2"></i><b>(2)</b>
|
||||
<maven-checkstyle-plugin.includeTestSourceDirectory>true
|
||||
</maven-checkstyle-plugin.includeTestSourceDirectory> <i class="conum" data-value="3"></i><b>(3)</b>
|
||||
</properties>
|
||||
<title>Page Redirection</title>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin> <i class="conum" data-value="4"></i><b>(4)</b>
|
||||
<groupId>io.spring.javaformat</groupId>
|
||||
<artifactId>spring-javaformat-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin> <i class="conum" data-value="5"></i><b>(5)</b>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin> <i class="conum" data-value="5"></i><b>(5)</b>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
</build></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colist arabic">
|
||||
<table>
|
||||
<tr>
|
||||
<td><i class="conum" data-value="1"></i><b>1</b></td>
|
||||
<td>Fails the build upon Checkstyle errors</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="conum" data-value="2"></i><b>2</b></td>
|
||||
<td>Fails the build upon Checkstyle violations</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="conum" data-value="3"></i><b>3</b></td>
|
||||
<td>Checkstyle analyzes also the test sources</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="conum" data-value="4"></i><b>4</b></td>
|
||||
<td>Add the Spring Java Format plugin that will reformat your code to pass most of the Checkstyle formatting rules</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="conum" data-value="5"></i><b>5</b></td>
|
||||
<td>Add checkstyle plugin to your build and reporting phases</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>If you need to suppress some rules (e.g. line length needs to be longer), then it’s enough for you to define a file under <code>${project.root}/src/checkstyle/checkstyle-suppressions.xml</code> with your suppressions. Example:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="title">projectRoot/src/checkstyle/checkstyle-suppresions.xml</div>
|
||||
<div class="content">
|
||||
<pre><?xml version="1.0"?>
|
||||
<!DOCTYPE suppressions PUBLIC
|
||||
"-//Puppy Crawl//DTD Suppressions 1.1//EN"
|
||||
"https://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
|
||||
<suppressions>
|
||||
<suppress files=".*ConfigServerApplication\.java" checks="HideUtilityClassConstructor"/>
|
||||
<suppress files=".*ConfigClientWatch\.java" checks="LineLengthCheck"/>
|
||||
</suppressions></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>It’s advisable to copy the <code>${spring-cloud-build.rootFolder}/.editorconfig</code> and <code>${spring-cloud-build.rootFolder}/.springformat</code> to your project. That way, some default formatting rules will be applied. You can do so by running this script:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ curl https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/.editorconfig -o .editorconfig
|
||||
$ touch .springformat</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_ide_setup"><a class="link" href="#_ide_setup">IDE setup</a></h3>
|
||||
<div class="sect3">
|
||||
<h4 id="_intellij_idea"><a class="link" href="#_intellij_idea">Intellij IDEA</a></h4>
|
||||
<div class="paragraph">
|
||||
<p>In order to setup Intellij you should import our coding conventions, inspection profiles and set up the checkstyle plugin.
|
||||
The following files can be found in the <a href="https://github.com/spring-cloud/spring-cloud-build/tree/master/spring-cloud-build-tools">Spring Cloud Build</a> project.</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="title">spring-cloud-build-tools/</div>
|
||||
<div class="content">
|
||||
<pre>└── src
|
||||
├── checkstyle
|
||||
│ └── checkstyle-suppressions.xml <i class="conum" data-value="3"></i><b>(3)</b>
|
||||
└── main
|
||||
└── resources
|
||||
├── checkstyle-header.txt <i class="conum" data-value="2"></i><b>(2)</b>
|
||||
├── checkstyle.xml <i class="conum" data-value="1"></i><b>(1)</b>
|
||||
└── intellij
|
||||
├── Intellij_Project_Defaults.xml <i class="conum" data-value="4"></i><b>(4)</b>
|
||||
└── Intellij_Spring_Boot_Java_Conventions.xml <i class="conum" data-value="5"></i><b>(5)</b></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colist arabic">
|
||||
<table>
|
||||
<tr>
|
||||
<td><i class="conum" data-value="1"></i><b>1</b></td>
|
||||
<td>Default Checkstyle rules</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="conum" data-value="2"></i><b>2</b></td>
|
||||
<td>File header setup</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="conum" data-value="3"></i><b>3</b></td>
|
||||
<td>Default suppression rules</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="conum" data-value="4"></i><b>4</b></td>
|
||||
<td>Project defaults for Intellij that apply most of Checkstyle rules</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="conum" data-value="5"></i><b>5</b></td>
|
||||
<td>Project style conventions for Intellij that apply most of Checkstyle rules</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="imageblock">
|
||||
<div class="content">
|
||||
<img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/images/intellij-code-style.png" alt="Code style">
|
||||
</div>
|
||||
<div class="title">Figure 1. Code style</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Go to <code>File</code> → <code>Settings</code> → <code>Editor</code> → <code>Code style</code>. There click on the icon next to the <code>Scheme</code> section. There, click on the <code>Import Scheme</code> value and pick the <code>Intellij IDEA code style XML</code> option. Import the <code>spring-cloud-build-tools/src/main/resources/intellij/Intellij_Spring_Boot_Java_Conventions.xml</code> file.</p>
|
||||
</div>
|
||||
<div class="imageblock">
|
||||
<div class="content">
|
||||
<img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/images/intellij-inspections.png" alt="Code style">
|
||||
</div>
|
||||
<div class="title">Figure 2. Inspection profiles</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Go to <code>File</code> → <code>Settings</code> → <code>Editor</code> → <code>Inspections</code>. There click on the icon next to the <code>Profile</code> section. There, click on the <code>Import Profile</code> and import the <code>spring-cloud-build-tools/src/main/resources/intellij/Intellij_Project_Defaults.xml</code> file.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<div class="title">Checkstyle</div>
|
||||
<p>To have Intellij work with Checkstyle, you have to install the <code>Checkstyle</code> plugin. It’s advisable to also install the <code>Assertions2Assertj</code> to automatically convert the JUnit assertions</p>
|
||||
</div>
|
||||
<div class="imageblock">
|
||||
<div class="content">
|
||||
<img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/images/intellij-checkstyle.png" alt="Checkstyle">
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Go to <code>File</code> → <code>Settings</code> → <code>Other settings</code> → <code>Checkstyle</code>. There click on the <code>+</code> icon in the <code>Configuration file</code> section. There, you’ll have to define where the checkstyle rules should be picked from. In the image above, we’ve picked the rules from the cloned Spring Cloud Build repository. However, you can point to the Spring Cloud Build’s GitHub repository (e.g. for the <code>checkstyle.xml</code> : <code><a href="https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle.xml" class="bare">https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle.xml</a></code>). We need to provide the following variables:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>checkstyle.header.file</code> - please point it to the Spring Cloud Build’s, <code>spring-cloud-build-tools/src/main/resources/checkstyle-header.txt</code> file either in your cloned repo or via the <code><a href="https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle-header.txt" class="bare">https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle-header.txt</a></code> URL.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>checkstyle.suppressions.file</code> - default suppressions. Please point it to the Spring Cloud Build’s, <code>spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml</code> file either in your cloned repo or via the <code><a href="https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml" class="bare">https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml</a></code> URL.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>checkstyle.additional.suppressions.file</code> - this variable corresponds to suppressions in your local project. E.g. you’re working on <code>spring-cloud-contract</code>. Then point to the <code>project-root/src/checkstyle/checkstyle-suppressions.xml</code> folder. Example for <code>spring-cloud-contract</code> would be: <code>/home/username/spring-cloud-contract/src/checkstyle/checkstyle-suppressions.xml</code>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="admonitionblock important">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-important" title="Important"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
Remember to set the <code>Scan Scope</code> to <code>All sources</code> since we apply checkstyle rules for production and test sources.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="_how_to_build_spring_cloud_contract"><a class="link" href="#_how_to_build_spring_cloud_contract">How to Build Spring Cloud Contract</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="admonitionblock important">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-important" title="Important"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
You need to have all the necessary Groovy plugins
|
||||
installed for your IDE to properly resolve the sources. For example, in
|
||||
Intellij IDEA, having both the Eclipse Groovy Compiler Plugin and the GMavenPlus Intellij
|
||||
Plugin results in properly imported project.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="admonitionblock important">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-important" title="Important"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
Spring Cloud Contract builds Docker images. Remember to
|
||||
have Docker installed.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</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 to run the build in offline mode, you must have Maven 3.5.2+ installed.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_project_structure"><a class="link" href="#_project_structure">Project structure</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>The following listing shows the Spring Cloud Contract folder structure:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code>├── config
|
||||
├── docker
|
||||
├── samples
|
||||
├── scripts
|
||||
├── specs
|
||||
├── spring-cloud-contract-dependencies
|
||||
├── spring-cloud-contract-shade
|
||||
├── spring-cloud-contract-starters
|
||||
├── spring-cloud-contract-stub-runner
|
||||
├── spring-cloud-contract-stub-runner-boot
|
||||
├── spring-cloud-contract-tools
|
||||
├── spring-cloud-contract-verifier
|
||||
├── spring-cloud-contract-wiremock
|
||||
└── tests</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The following list describes each of the top-level folders in the project structure:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>config</code>: Folder contains setup for Spring Cloud Release Tools automated release process</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>docker</code>: Folder contains docker images</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>samples</code>: Folder contains test samples together with standalone ones used also to build documentation</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>scripts</code>: Contains scripts to build and test <code>Spring Cloud Contract</code> with Maven, Gradle and standalone projects</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>specs</code>: Contains specifications for the Contract DSL.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-dependencies</code>: Contains Spring Cloud Contract BOM</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-shade</code>: Shaded dependencies used by the plugins</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-starters</code>: Contains Spring Cloud Contract Starters</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-spec</code>: Contains specification modules (contains concept of a Contract)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-stub-runner</code>: Contains Stub Runner related modules</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-stub-runner-boot</code>: Contains Stub Runner Boot app</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-tools</code>: Gradle and Maven plugin for <code>Spring Cloud Contract Verifier</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-verifier</code>: Core of the <code>Spring Cloud Contract Verifier</code> functionality</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-wiremock</code>: All WireMock related functionality</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>tests</code>: Integration tests for different messaging technologies</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_commands"><a class="link" href="#_commands">Commands</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>To build the core functionality together with the Maven Plugin, you can run the following
|
||||
command:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code>./mvnw clean install -P integration</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Calling that function builds the core, the Maven plugin, and the Gradle plugin and runs
|
||||
end-to_end tests on the
|
||||
standalone samples in the proper order (both for Maven and Gradle).</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To build only the Gradle Plugin, you can run the following commands:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code>cd spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin
|
||||
./gradlew clean build</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_helpful_scripts"><a class="link" href="#_helpful_scripts">Helpful scripts</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>We provide a couple of helpful scripts to build the project.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To build the project in parallel (by default, it uses four cores, but you can change it),
|
||||
run the following command:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code>./scripts/parallelBuild.sh</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To use eight 8 cores, run thke following command:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code>CORES=8 ./scripts/parallelBuild.sh</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To build the project without any integration tests (by default, this uses one core), run
|
||||
the following command:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code>./scripts/noIntegration.sh</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To use eight cores, run the following command:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code>CORES=8 ./scripts/noIntegration.sh</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To generate the documentation (for both the root project and the maven plugin), run the
|
||||
following command:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code>./scripts/generateDocs.sh</code></pre>
|
||||
</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/github.min.css">
|
||||
<script src="js/highlight/highlight.min.js"></script>
|
||||
<script>hljs.initHighlighting()</script>
|
||||
</body>
|
||||
</html>
|
||||
If you are not redirected automatically, follow the <a href='https://spring.io/projects/spring-cloud-contract#learn'>link to docs</a>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,457 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<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.8">
|
||||
<title>Common application properties</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};
|
||||
}
|
||||
|
||||
function globalSwitch() {
|
||||
$('.switch--item').each(function() {
|
||||
$(this).off('click');
|
||||
$(this).on('click', function() {
|
||||
selectedText = $(this).text()
|
||||
selectedIndex = $(this).index()
|
||||
$(".switch--item").filter(function() { return ($(this).text() === selectedText) }).each(function() {
|
||||
$(this).addClass('selected');
|
||||
$(this).siblings().removeClass('selected');
|
||||
selectedContent = $(this).parent().siblings(".content").eq(selectedIndex)
|
||||
selectedContent.removeClass('hidden');
|
||||
selectedContent.siblings().addClass('hidden');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(addBlockSwitches);
|
||||
$(globalSwitch);
|
||||
<meta http-equiv="refresh" content="1; url=https://spring.io/projects/spring-cloud-contract#learn">
|
||||
|
||||
<script>
|
||||
window.location.href = "https://spring.io/projects/spring-cloud-contract#learn"
|
||||
</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="#common-application-properties">Appendix A: Common application properties</a>
|
||||
<ul class="sectlevel2">
|
||||
<li><a href="#default-application-properties">A.1. Default application properties</a></li>
|
||||
<li><a href="#additional-application-properties">A.2. Additional application properties</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div class="sect1">
|
||||
<h2 id="common-application-properties"><a class="link" href="#common-application-properties">Appendix A: Common application properties</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>Various properties can be specified inside your <code>application.properties</code> file, inside your <code>application.yml</code> file, or as command line switches.
|
||||
This appendix provides a list of common Spring Cloud Contract properties and references to the underlying classes that consume them.</p>
|
||||
</div>
|
||||
<div class="admonitionblock note">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-note" title="Note"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
Property contributions can come from additional jar files on your classpath, so you should not consider this an exhaustive list.
|
||||
Also, you can define your own properties.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="default-application-properties"><a class="anchor" href="#default-application-properties"></a><a class="link" href="#default-application-properties">A.1. Default application properties</a></h3>
|
||||
<table class="tableblock frame-all 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">Name</th>
|
||||
<th class="tableblock halign-left valign-top">Default</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.amqp.enabled</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">Whether to enable support for Stub Runner and AMQP.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.amqp.mockCOnnection</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Whether to enable support for Stub Runner and AMQP mocked connection factory.</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">The classifier to use by default in ivy co-ordinates for a stub.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.cloud.consul.enabled</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Whether to enable stubs registration in Consul.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.cloud.delegate.enabled</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Whether to enable DiscoveryClient’s Stub Runner implementation.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.cloud.enabled</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Whether to enable Spring Cloud support for Stub Runner.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.cloud.eureka.enabled</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Whether to enable stubs registration in Eureka.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.cloud.loadbalancer.enabled</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Whether to enable Stub Runner’s Spring Cloud Load Balancer integration.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.cloud.stubbed.discovery.enabled</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Whether Service Discovery should be stubbed for Stub Runner. If set to false, stubs will get registered in real service discovery.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.cloud.zookeeper.enabled</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Whether to enable stubs registration in Zookeeper.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.consumer-name</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">You can override the default {@code spring.application.name} of this field by setting a value to this parameter.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.delete-stubs-after-test</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">If set to {@code false} will NOT delete stubs from a temporary folder after running tests.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.fail-on-no-stubs</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">When enabled, this flag will tell stub runner to throw an exception when no stubs / contracts were found.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.generate-stubs</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">When enabled, this flag will tell stub runner to not load the generated stubs, but convert the found contracts at runtime to a stub format and run those stubs.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.http-server-stub-configurer</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Configuration for an HTTP server stub.</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"><p class="tableblock">[]</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">The ids of the stubs to run in "ivy" notation ([groupId]:artifactId:[version]:[classifier][:port]). {@code groupId}, {@code classifier}, {@code version} and {@code port} can be optional.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.ids-to-service-ids</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Mapping of Ivy notation based ids to serviceIds inside your application. Example "a:b" → "myService" "artifactId" → "myOtherService"</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.integration.enabled</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Whether to enable Stub Runner integration with Spring Integration.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.jms.enabled</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Whether to enable Stub Runner integration with Spring JMS.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.kafka.enabled</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Whether to enable Stub Runner integration with Spring Kafka.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.kafka.initializer.enabled</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Whether to allow Stub Runner to take care of polling for messages instead of the KafkaStubMessages component. The latter should be used only on the producer side.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.mappings-output-folder</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Dumps the mappings of each HTTP server to the selected folder.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.max-port</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">Max value of a port for the automatically started WireMock server.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.min-port</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">Min value of a port for the automatically started WireMock server.</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">Repository password.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.properties</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Map of properties that can be passed to custom {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.proxy-host</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Repository proxy host.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.proxy-port</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Repository proxy port.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.server-id</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.stream.enabled</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Whether to enable Stub Runner integration with Spring Cloud Stream.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.stubs-mode</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Pick where the stubs should come from.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.stubs-per-consumer</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">Should only stubs for this particular consumer get registered in HTTP server stub.</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">Repository username.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">wiremock.placeholders.enabled</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Flag to indicate that http URLs in generated wiremock stubs should be filtered to add or resolve a placeholder for a dynamic port.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">wiremock.reset-mappings-after-each-test</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">wiremock.rest-template-ssl-enabled</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">wiremock.server.files</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">[]</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">wiremock.server.https-port</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">-1</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">wiremock.server.https-port-dynamic</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">wiremock.server.port</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">8080</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">wiremock.server.port-dynamic</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">wiremock.server.stubs</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">[]</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="additional-application-properties"><a class="anchor" href="#additional-application-properties"></a><a class="link" href="#additional-application-properties">A.2. Additional application properties</a></h3>
|
||||
<div class="admonitionblock important">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-important" title="Important"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
The following properties can be passed as a system property (e.g. <code>stubrunner.properties.git.branch</code>) or via an environment variable (e.g. <code>STUBRUNNER_PROPERTIES_GIT_BRANCH</code>) or as a property inside stub runner’s annotation or a JUnit Rule / Extension. In the latter case you can pass <code>git.branch</code> property name instead of the <code>stubrunner.properties.git.branch</code> one.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<table class="tableblock frame-all grid-all stretch">
|
||||
<caption class="title">Table 1. Stubrunner Properties Options</caption>
|
||||
<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">Name</th>
|
||||
<th class="tableblock halign-left valign-top">Default</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.properties.pactbroker.provider-name-with-group-id</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">When using the Pact Broker based approach, you can automatically group id to the provider name.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.properties.git.branch</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">When using the SCM based approach, you can customize the branch name to check out.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.properties.git.commit-message</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Updating project [$project] with stubs</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">When using the SCM based approach, you can customize the commit message for created stubs. The <code>$project</code> text will be replaced with the project name.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.properties.git.no-of-attempts</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">10</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">When using the SCM based approach, you can customize number of retries to push the stubs to Git.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.properties.git.username</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">When using the SCM based approach, you can pass the username to connect to the Git repository.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.properties.git.password</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">When using the SCM based approach, you can pass the password to connect to the Git repository.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.properties.git.wait-between-attempts</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">1000</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">When using the SCM based approach, you can customize waiting time in ms between trying to push the stubs to Git.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">stubrunner.properties.stubs.find-producer</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">When using the Stubs protocol, you can toggle this flag to search for contracts via the <code>group id / artifact id</code> instead of taking the stubs directly from the provided folder.</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</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/github.min.css">
|
||||
<script src="js/highlight/highlight.min.js"></script>
|
||||
<script>hljs.initHighlighting()</script>
|
||||
</body>
|
||||
</html>
|
||||
<title>Page Redirection</title>
|
||||
|
||||
If you are not redirected automatically, follow the <a href='https://spring.io/projects/spring-cloud-contract#learn'>link to docs</a>
|
||||
|
||||
@@ -1,304 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<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>How to build it</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">
|
||||
<meta http-equiv="refresh" content="1; url=https://spring.io/projects/spring-cloud-contract#learn">
|
||||
|
||||
<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>
|
||||
window.location.href = "https://spring.io/projects/spring-cloud-contract#learn"
|
||||
</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="#_how_to_build_it">How to build it</a>
|
||||
<ul class="sectlevel2">
|
||||
<li><a href="#_project_structure">Project structure</a></li>
|
||||
<li><a href="#_commands">Commands</a></li>
|
||||
<li><a href="#_helpful_scripts">Helpful scripts</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div class="sect1">
|
||||
<h2 id="_how_to_build_it"><a class="link" href="#_how_to_build_it">How to build it</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="admonitionblock important">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-important" title="Important"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
You need to have all the necessary Groovy plugins
|
||||
installed for your IDE to properly resolve the sources. For example in
|
||||
Intellij IDEA having both Eclipse Groovy Compiler Plugin & GMavenPlus Intellij Plugin
|
||||
results in properly imported project.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="admonitionblock important">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-important" title="Important"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
Spring Cloud Contract builds Docker images. Remember to
|
||||
have Docker installed.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</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 to run the build in offline mode, you have to have Maven 3.5.2+ installed.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_project_structure"><a class="link" href="#_project_structure">Project structure</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>Here you can find the Spring Cloud Contract folder structure</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code>├── config
|
||||
├── docker
|
||||
├── samples
|
||||
├── scripts
|
||||
├── specs
|
||||
├── spring-cloud-contract-dependencies
|
||||
├── spring-cloud-contract-shade
|
||||
├── spring-cloud-contract-starters
|
||||
├── spring-cloud-contract-stub-runner
|
||||
├── spring-cloud-contract-stub-runner-boot
|
||||
├── spring-cloud-contract-tools
|
||||
├── spring-cloud-contract-verifier
|
||||
├── spring-cloud-contract-wiremock
|
||||
└── tests</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>config</code> - folder contains setup for Spring Cloud Release Tools automated release process</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>docker</code> - folder contains docker images</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>samples</code> - folder contains test samples together with standalone ones used also to build documentation</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>scripts</code> - contains scripts to build and test <code>Spring Cloud Contract</code> with Maven, Gradle and standalone projects</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>specs</code> - contains specifications for the Contract DSL.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-dependencies</code> - contains Spring Cloud Contract BOM</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-shade</code> - shaded dependencies used by the plugins</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-starters</code> - contains Spring Cloud Contract Starters</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-spec</code> - contains specification modules (contains concept of a Contract)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-stub-runner</code> - contains Stub Runner related modules</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-stub-runner-boot</code> - contains Stub Runner Boot app</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-tools</code> - Gradle and Maven plugin for <code>Spring Cloud Contract Verifier</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-verifier</code> - core of the <code>Spring Cloud Contract Verifier</code> functionality</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>spring-cloud-contract-wiremock</code> - all WireMock related functionality</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>tests</code> - integration tests for different messaging technologies</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_commands"><a class="link" href="#_commands">Commands</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>To build the core functionality together with Maven Plugin you can run</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code>./mvnw clean install -P integration</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Calling that function will build core, Maven plugin, Gradle plugin and run end to end tests on the
|
||||
standalone samples in proper order (both for Maven and Gradle).</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To build the Gradle Plugin only</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code>cd spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin
|
||||
./gradlew clean build</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_helpful_scripts"><a class="link" href="#_helpful_scripts">Helpful scripts</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>We’re providing a couple of helpful scripts to build the project.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To build the project in parallel (by default uses 4 cores but you can change it)</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code>./scripts/parallelBuild.sh</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>and with 8 cores</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code>CORES=8 ./scripts/parallelBuild.sh</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To build the project without any integration tests (by default uses 1 core)</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code>./scripts/noIntegration.sh</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>and with 8 cores</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code>CORES=8 ./scripts/noIntegration.sh</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To generate the documentation (both the root one and the maven plugin one)</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code>./scripts/generateDocs.sh</code></pre>
|
||||
</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>
|
||||
<title>Page Redirection</title>
|
||||
|
||||
If you are not redirected automatically, follow the <a href='https://spring.io/projects/spring-cloud-contract#learn'>link to docs</a>
|
||||
|
||||
@@ -1,607 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<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.8">
|
||||
<title>Docker Project</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};
|
||||
}
|
||||
|
||||
function globalSwitch() {
|
||||
$('.switch--item').each(function() {
|
||||
$(this).off('click');
|
||||
$(this).on('click', function() {
|
||||
selectedText = $(this).text()
|
||||
selectedIndex = $(this).index()
|
||||
$(".switch--item").filter(function() { return ($(this).text() === selectedText) }).each(function() {
|
||||
$(this).addClass('selected');
|
||||
$(this).siblings().removeClass('selected');
|
||||
selectedContent = $(this).parent().siblings(".content").eq(selectedIndex)
|
||||
selectedContent.removeClass('hidden');
|
||||
selectedContent.siblings().addClass('hidden');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(addBlockSwitches);
|
||||
$(globalSwitch);
|
||||
<meta http-equiv="refresh" content="1; url=https://spring.io/projects/spring-cloud-contract#learn">
|
||||
|
||||
<script>
|
||||
window.location.href = "https://spring.io/projects/spring-cloud-contract#learn"
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body id="docker" class="book toc2 toc-left">
|
||||
<div id="header">
|
||||
<h1>Docker Project</h1>
|
||||
<div id="toc" class="toc2">
|
||||
<div id="toctitle">Table of Contents</div>
|
||||
<ul class="sectlevel1">
|
||||
<li><a href="#docker-intro">1. A Short Introduction to Maven, JARs and Binary storage</a></li>
|
||||
<li><a href="#docker-how-it-works">2. Generating Tests on the Producer Side</a>
|
||||
<ul class="sectlevel2">
|
||||
<li><a href="#docker-env-vars">2.1. Environment Variables</a></li>
|
||||
<li><a href="#docker-example-of-usage">2.2. Example of Usage</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#docker-stubrunner">3. Running Stubs on the Consumer Side</a>
|
||||
<ul class="sectlevel2">
|
||||
<li><a href="#docker-stubrunner-env-vars">3.1. Environment Variables</a></li>
|
||||
<li><a href="#docker-stubrunner-example">3.2. Example of Usage</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div id="preamble">
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>In this section, we publish a <code>springcloud/spring-cloud-contract</code> Docker image
|
||||
that contains a project that generates tests and runs them in <code>EXPLICIT</code> mode
|
||||
against a running application.</p>
|
||||
</div>
|
||||
<div class="admonitionblock tip">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-tip" title="Tip"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
The <code>EXPLICIT</code> mode means that the tests generated from contracts send
|
||||
real requests and not the mocked ones.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>We also publish a <code>spring-cloud/spring-cloud-contract-stub-runner</code> Docker image
|
||||
that starts the standalone version of Stub Runner.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="docker-intro"><a class="anchor" href="#docker-intro"></a><a class="link" href="#docker-intro">1. A Short Introduction to Maven, JARs and Binary storage</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>Since non-JVM projects can use the Docker image, it is good to
|
||||
explain the basic terms behind Spring Cloud Contract packaging defaults.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Parts of the following definitions were taken from the <a href="https://maven.apache.org/glossary.html">Maven Glossary</a>:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>Project</code>: Maven thinks in terms of projects. Projects
|
||||
are all you build. Those projects follow a well defined
|
||||
“Project Object Model”. Projects can depend on other projects,
|
||||
in which case the latter are called “dependencies”. A project may
|
||||
consistent of several subprojects. However, these subprojects are still
|
||||
treated equally as projects.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>Artifact</code>: An artifact is something that is either produced or used
|
||||
by a project. Examples of artifacts produced by Maven for a project
|
||||
include JAR files and source and binary distributions. Each artifact
|
||||
is uniquely identified by a group ID and an artifact ID that is
|
||||
unique within a group.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>JAR</code>: JAR stands for Java ARchive. Its format is based on
|
||||
the ZIP file format. Spring Cloud Contract packages the contracts and generated
|
||||
stubs in a JAR file.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>GroupId</code>: A group ID is a universally unique identifier for a project.
|
||||
While this is often just the project name (for example, <code>commons-collections</code>),
|
||||
it is helpful to use a fully-qualified package name to distinguish it
|
||||
from other projects with a similar name (for example, <code>org.apache.maven</code>).
|
||||
Typically, when published to the Artifact Manager, the <code>GroupId</code> gets
|
||||
slash separated and forms part of the URL. For example, for a group ID of <code>com.example</code>
|
||||
and an artifact ID of <code>application</code>, the result would be <code>/com/example/application/</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>Classifier</code>: The Maven dependency notation looks as follows:
|
||||
<code>groupId:artifactId:version:classifier</code>. The classifier is an additional suffix
|
||||
passed to the dependency — for example, <code>stubs</code> or <code>sources</code>. The same dependency
|
||||
(for example, <code>com.example:application</code>) can produce multiple artifacts that
|
||||
differ from each other with the classifier.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>Artifact manager</code>: When you generate binaries, sources, or packages, you would
|
||||
like them to be available for others to download, reference, or reuse. In the case
|
||||
of the JVM world, those artifacts are generally JARs. For Ruby, those artifacts are gems.
|
||||
For Docker, those artifacts are Docker images. You can store those artifacts
|
||||
in a manager. Examples of such managers include <a href="https://jfrog.com/artifactory/">Artifactory</a>
|
||||
or <a href="https://www.sonatype.org/nexus/">Nexus</a>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="docker-how-it-works"><a class="anchor" href="#docker-how-it-works"></a><a class="link" href="#docker-how-it-works">2. Generating Tests on the Producer Side</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>The image searches for contracts under the <code>/contracts</code> folder.
|
||||
The output from running the tests is available in the
|
||||
<code>/spring-cloud-contract/build</code> folder (useful for debugging
|
||||
purposes).</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>You can mount your contracts and pass the environment variables.
|
||||
The image then:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>Generates the contract tests</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Runs the tests against the provided URL</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Generates the <a href="https://github.com/tomakehurst/wiremock">WireMock</a> stubs</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Publishes the stubs to a Artifact Manager (optional - turned on by default)</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="docker-env-vars"><a class="anchor" href="#docker-env-vars"></a><a class="link" href="#docker-env-vars">2.1. Environment Variables</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>The Docker image requires some environment variables to point to
|
||||
your running application, to the Artifact manager instance, and so on.
|
||||
The following list describes the environment variables:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>PROJECT_GROUP</code>: Your project’s group ID. Defaults to <code>com.example</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>PROJECT_VERSION</code>: Your project’s version. Defaults to <code>0.0.1-SNAPSHOT</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>PROJECT_NAME</code>: Your project’s artifact id. Defaults to <code>example</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>PRODUCER_STUBS_CLASSIFIER</code>: Archive classifier used for generated producer stubs. Defaults to <code>stubs</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>REPO_WITH_BINARIES_URL</code>: URL of your Artifact Manager. Defaults to <code><a href="http://localhost:8081/artifactory/libs-release-local" class="bare">localhost:8081/artifactory/libs-release-local</a></code>,
|
||||
which is the default URL of <a href="https://jfrog.com/artifactory/">Artifactory</a> running locally.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>REPO_WITH_BINARIES_USERNAME</code>: (optional) Username when the Artifact Manager is secured. Defaults to <code>admin</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>REPO_WITH_BINARIES_PASSWORD</code>: (optional) Password when the Artifact Manager is secured. Defaults to <code>password</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>PUBLISH_ARTIFACTS</code>: If set to <code>true</code>, publishes the artifact to binary storage. Defaults to <code>true</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>PUBLISH_ARTIFACTS_OFFLINE</code>: If set to <code>true</code>, it will publish the artifacts to local <code>.m2</code>. Defaults to <code>false</code>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>These environment variables are used when contracts lay in an external repository. To enable
|
||||
this feature, you must set the <code>EXTERNAL_CONTRACTS_ARTIFACT_ID</code> environment variable.</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>EXTERNAL_CONTRACTS_GROUP_ID</code>: Group ID of the project with contracts. Defaults to <code>com.example</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>EXTERNAL_CONTRACTS_ARTIFACT_ID</code>: Artifact ID of the project with contracts.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>EXTERNAL_CONTRACTS_CLASSIFIER</code>: Classifier of the project with contracts. Empty by default.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>EXTERNAL_CONTRACTS_VERSION</code>: Version of the project with contracts. Defaults to <code>+</code>, equivalent to picking the latest.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL</code>: URL of your Artifact Manager. It defaults to
|
||||
the value of <code>REPO_WITH_BINARIES_URL</code> environment variable.
|
||||
If that is not set, it defaults to <code><a href="http://localhost:8081/artifactory/libs-release-local" class="bare">localhost:8081/artifactory/libs-release-local</a></code>,
|
||||
which is the default URL of <a href="https://jfrog.com/artifactory/">Artifactory</a> running locally.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_USERNAME</code>: (optional) Username if the <code>EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL</code>
|
||||
requires authentication. It defaults to <code>REPO_WITH_BINARIES_USERNAME</code>. If that is not set, it defaults to <code>admin</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_PASSWORD</code>: (optional) Password if the <code>EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL</code>
|
||||
requires authentication. It defaults to <code>REPO_WITH_BINARIES_PASSWORD</code>. If that is not set, it defaults to <code>password</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>EXTERNAL_CONTRACTS_PATH</code>: Path to contracts for the given project, inside the project with contracts.
|
||||
Defaults to slash-separated <code>EXTERNAL_CONTRACTS_GROUP_ID</code> concatenated with <code>/</code> and <code>EXTERNAL_CONTRACTS_ARTIFACT_ID</code>. For example,
|
||||
for group id <code>cat-server-side.dog</code> and artifact id <code>fish</code>, would result in <code>cat/dog/fish</code> for the contracts path.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>EXTERNAL_CONTRACTS_WORK_OFFLINE</code>; If set to <code>true</code>, retrieves the artifact with contracts
|
||||
from the container’s <code>.m2</code>. Mount your local <code>.m2</code> as a volume available at the container’s <code>/root/.m2</code> path.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="admonitionblock warning">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-warning" title="Warning"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
You must not set both <code>EXTERNAL_CONTRACTS_WORK_OFFLINE</code> and <code>EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL</code>.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The following environment variables are used when tests are executed:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>APPLICATION_BASE_URL</code>: URL against which tests should be run.
|
||||
Remember that it has to be accessible from the Docker container (for example, <code>localhost</code>
|
||||
does not work)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>APPLICATION_USERNAME</code>: (optional) Username for basic authentication to your application.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>APPLICATION_PASSWORD</code>: (optional) Password for basic authentication to your application.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="docker-example-of-usage"><a class="anchor" href="#docker-example-of-usage"></a><a class="link" href="#docker-example-of-usage">2.2. Example of Usage</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>In this section, we explore a simple MVC application. To get started, clone the following
|
||||
git repository and cd to the resulting directory, by running the following commands:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<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>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The contracts are available in the <code>/contracts</code> folder.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Since we want to run tests, we can run the following command:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ npm test</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>However, for learning purposes, we split it into pieces, as follows:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash"># Stop docker infra (nodejs, artifactory)
|
||||
$ ./stop_infra.sh
|
||||
# Start docker infra (nodejs, artifactory)
|
||||
$ ./setup_infra.sh
|
||||
<title>Page Redirection</title>
|
||||
|
||||
# Kill & Run app
|
||||
$ pkill -f "node app"
|
||||
$ nohup node app &
|
||||
|
||||
# Prepare environment variables
|
||||
$ SC_CONTRACT_DOCKER_VERSION="..."
|
||||
$ APP_IP="192.168.0.100"
|
||||
$ APP_PORT="3000"
|
||||
$ ARTIFACTORY_PORT="8081"
|
||||
$ APPLICATION_BASE_URL="http://${APP_IP}:${APP_PORT}"
|
||||
$ ARTIFACTORY_URL="http://${APP_IP}:${ARTIFACTORY_PORT}/artifactory/libs-release-local"
|
||||
$ CURRENT_DIR="$( pwd )"
|
||||
$ CURRENT_FOLDER_NAME=${PWD##*/}
|
||||
$ PROJECT_VERSION="0.0.1.RELEASE"
|
||||
|
||||
# Execute contract tests
|
||||
$ docker run --rm -e "APPLICATION_BASE_URL=${APPLICATION_BASE_URL}" -e "PUBLISH_ARTIFACTS=true" -e "PROJECT_NAME=${CURRENT_FOLDER_NAME}" -e "REPO_WITH_BINARIES_URL=${ARTIFACTORY_URL}" -e "PROJECT_VERSION=${PROJECT_VERSION}" -v "${CURRENT_DIR}/contracts/:/contracts:ro" -v "${CURRENT_DIR}/node_modules/spring-cloud-contract/output:/spring-cloud-contract-output/" springcloud/spring-cloud-contract:"${SC_CONTRACT_DOCKER_VERSION}"
|
||||
|
||||
# Kill app
|
||||
$ pkill -f "node app"</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Through bash scripts, the following happens:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>The infrastructure (MongoDb and Artifactory) is set up.
|
||||
In a real-life scenario, you would run the NodeJS application
|
||||
with a mocked database. In this example, we want to show how we can
|
||||
benefit from Spring Cloud Contract in very little time.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Due to those constraints, the contracts also represent the
|
||||
stateful situation.</p>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>The first request is a <code>POST</code> that causes data to get inserted to the database.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>The second request is a <code>GET</code> that returns a list of data with 1 previously inserted element.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<p>The NodeJS application is started (on port <code>3000</code>).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>The contract tests are generated through Docker, and tests
|
||||
are run against the running application.</p>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>The contracts are taken from <code>/contracts</code> folder.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>The output of the test execution is available under
|
||||
<code>node_modules/spring-cloud-contract/output</code>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<p>The stubs are uploaded to Artifactory. You can find them in
|
||||
<a href="http://localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/" class="bare">localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/</a> .
|
||||
The stubs are at <a href="http://localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/bookstore-0.0.1.RELEASE-stubs.jar" class="bare">localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/bookstore-0.0.1.RELEASE-stubs.jar</a>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="docker-stubrunner"><a class="anchor" href="#docker-stubrunner"></a><a class="link" href="#docker-stubrunner">3. Running Stubs on the Consumer Side</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>This section describes how to use Docker on the consumer side to fetch and run stubs.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>We publish a <code>spring-cloud/spring-cloud-contract-stub-runner</code> Docker image
|
||||
that starts the standalone version of Stub Runner.</p>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="docker-stubrunner-env-vars"><a class="anchor" href="#docker-stubrunner-env-vars"></a><a class="link" href="#docker-stubrunner-env-vars">3.1. Environment Variables</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>You can run the docker image and pass any of the <a href="project-features.html#features-stub-runner-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 dot (<code>.</code>) should be replaced with underscore (<code>_</code>) characters. For example,
|
||||
the <code>stubrunner.repositoryRoot</code> property should be represented
|
||||
as a <code>STUBRUNNER_REPOSITORY_ROOT</code> environment variable.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="docker-stubrunner-example"><a class="anchor" href="#docker-stubrunner-example"></a><a class="link" href="#docker-stubrunner-example">3.2. Example of Usage</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>We want to use the stubs created in this <a href="#docker-server-side">[docker-server-side]</a> step.
|
||||
Assume that we want to run the stubs on port <code>9876</code>. You can see the NodeJS code
|
||||
by cloning the repository and changing to the directory indicated in the following commands:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<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>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Now we can run the Stub Runner Boot application with the stubs, by running the following
|
||||
commands:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<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>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>When the preceding commands run,</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>A standalone Stub Runner application gets started.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>It downloads the stub with coordinates <code>com.example:bookstore:0.0.1.RELEASE:stubs</code> on port <code>9876</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>It gets downloads from Artifactory running at <code><a href="http://192.168.0.100:8081/artifactory/libs-release-local" class="bare">192.168.0.100:8081/artifactory/libs-release-local</a></code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>After a whil, Stub Runner is running on port <code>8083</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>The stubs are running at port <code>9876</code>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>On the server side, we built a stateful stub. We can use curl to assert
|
||||
that the stubs are setup properly. To do so, run the following commands:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<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>
|
||||
</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,
|
||||
you should set the <code>-e STUBRUNNER_STUBS_MODE=LOCAL</code> environment variable and mount
|
||||
the volume of your local m2 (<code>-v "${HOME}/.m2/:/root/.m2:ro"</code>).
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</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/github.min.css">
|
||||
<script src="js/highlight/highlight.min.js"></script>
|
||||
<script>hljs.initHighlighting()</script>
|
||||
</body>
|
||||
</html>
|
||||
If you are not redirected automatically, follow the <a href='https://spring.io/projects/spring-cloud-contract#learn'>link to docs</a>
|
||||
|
||||
@@ -1,391 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<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.8">
|
||||
<title>Spring Cloud Contract Documentation</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};
|
||||
}
|
||||
|
||||
function globalSwitch() {
|
||||
$('.switch--item').each(function() {
|
||||
$(this).off('click');
|
||||
$(this).on('click', function() {
|
||||
selectedText = $(this).text()
|
||||
selectedIndex = $(this).index()
|
||||
$(".switch--item").filter(function() { return ($(this).text() === selectedText) }).each(function() {
|
||||
$(this).addClass('selected');
|
||||
$(this).siblings().removeClass('selected');
|
||||
selectedContent = $(this).parent().siblings(".content").eq(selectedIndex)
|
||||
selectedContent.removeClass('hidden');
|
||||
selectedContent.siblings().addClass('hidden');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(addBlockSwitches);
|
||||
$(globalSwitch);
|
||||
<meta http-equiv="refresh" content="1; url=https://spring.io/projects/spring-cloud-contract#learn">
|
||||
|
||||
<script>
|
||||
window.location.href = "https://spring.io/projects/spring-cloud-contract#learn"
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body id="documentation" class="book toc2 toc-left">
|
||||
<div id="header">
|
||||
<h1>Spring Cloud Contract Documentation</h1>
|
||||
<div id="toc" class="toc2">
|
||||
<div id="toctitle">Table of Contents</div>
|
||||
<ul class="sectlevel1">
|
||||
<li><a href="#contract-documentation-about">1. About the Documentation</a></li>
|
||||
<li><a href="#documentation-getting-help">2. Getting Help</a></li>
|
||||
<li><a href="#contract-documentation-first-steps">3. First Steps</a></li>
|
||||
<li><a href="#working-with-spring-cloud-contract">4. Working with Spring Cloud Contract</a></li>
|
||||
<li><a href="#learning-about-spring-cloud-contract-features">5. Learning about Spring Cloud Contract Features</a></li>
|
||||
<li><a href="#advanced-topics">6. Advanced Topics</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div id="preamble">
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>This section provides a brief overview of Spring Cloud Contract reference documentation. It serves
|
||||
as a map for the rest of the document.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="contract-documentation-about"><a class="anchor" href="#contract-documentation-about"></a><a class="link" href="#contract-documentation-about">1. About the Documentation</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>The Spring Cloud Contract reference guide is available as</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><a href="https://docs.spring.io/spring-cloud-contract/docs/3.0.0-SNAPSHOT/reference/html">Multi-page HTML</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="https://docs.spring.io/spring-cloud-contract/docs/3.0.0-SNAPSHOT/reference/htmlsingle">Single-page HTML</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="https://docs.spring.io/spring-cloud-contract/docs/3.0.0-SNAPSHOT/reference/pdf/spring-cloud-contract.pdf">PDF</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Copies of this document may be made for your own use and for distribution to others,
|
||||
provided that you do not charge any fee for such copies and further provided that each
|
||||
copy contains this Copyright Notice, whether distributed in print or electronically.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="documentation-getting-help"><a class="anchor" href="#documentation-getting-help"></a><a class="link" href="#documentation-getting-help">2. Getting Help</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>If you have trouble with Spring Cloud Contract, we would like to help.</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>Try the <a href="howto.html#howto">How-to documents</a>. They provide solutions to the most
|
||||
common questions.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Learn the Spring Cloud Contract basics. If you are
|
||||
starting out with Spring Cloud Contract, try one of the <a href="https://spring.io/guides">guides</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Ask a question. We monitor <a href="https://stackoverflow.com">stackoverflow.com</a> for questions
|
||||
tagged with <a href="https://stackoverflow.com/tags/spring-cloud-contract"><code>spring-cloud-contract</code></a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Report bugs with Spring Cloud Contract at <a href="https://github.com/spring-cloud/spring-cloud-contract/issues" class="bare">github.com/spring-cloud/spring-cloud-contract/issues</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Chat with us at <a href="http://https://gitter.im/spring-cloud/spring-cloud-contract">Spring Cloud Contract Gitter</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="admonitionblock note">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-note" title="Note"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
All of Spring Cloud Contract is open source, including the documentation. If you find
|
||||
problems with the docs or if you want to improve them, please <a href="https://github.com/spring-cloud/spring-cloud-contract/tree/master">get
|
||||
involved</a>.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="contract-documentation-first-steps"><a class="anchor" href="#contract-documentation-first-steps"></a><a class="link" href="#contract-documentation-first-steps">3. First Steps</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>If you are getting started with Spring Cloud Contract or 'Spring' in general, start with
|
||||
<a href="getting-started.html#getting-started">the following topics</a>:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><strong>From scratch:</strong>
|
||||
<a href="getting-started.html#getting-started-introducing-spring-cloud-contract">Overview</a> |
|
||||
<a href="getting-started.html#getting-started-three-second-tour">Three-second Tour</a> |
|
||||
<a href="getting-started.html#getting-started-first-application">First application</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Tutorial:</strong>
|
||||
<a href="getting-started.html#getting-started-cdc">Introduction</a> |
|
||||
<a href="getting-started.html#consumer-side-loan-issuance">Consumer, Part 1</a> |
|
||||
<a href="getting-started.html#producer-side-fraud-detection-server">Producer</a> |
|
||||
<a href="getting-started.html#consumer-side-loan-issuance-final-step">Consumer, Part 2</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="working-with-spring-cloud-contract"><a class="anchor" href="#working-with-spring-cloud-contract"></a><a class="link" href="#working-with-spring-cloud-contract">4. Working with Spring Cloud Contract</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>Ready to actually start using Spring Cloud Contract? <a href="using.html#using">We have
|
||||
you covered</a>:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><strong>Provider contract testing:</strong></p>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><a href="using.html#flows-provider-nexus">Provider contract testing with stubs in Nexus or Artifactory</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="using.html#flows-provider-git">Provider contract testing with stubs in Git</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="using.html#flows-provider-non-spring">Provider contract testing with stubs in Artifactory for a non-Spring application</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="using.html#flows-provider-non-jvm">Provider contract testing with stubs in Artifactory in non JVM world</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="using.html#flows-provider-rest-docs">Provider contract testing with REST Docs and stubs in Nexus / Artifactory</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Consumer-Driven contract testing:</strong></p>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><a href="using.html#flows-cdc-contracts-producer">Consumer Driven Contracts with contracts on the producer side</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="using.html#flows-cdc-contracts-external">Consumer Driven Contracts with contracts in external repo</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="using.html#flows-cdc-contracts-stubs-git">Consumer Driven Contracts with contracts on the producer side, pushed to git</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="admonitionblock tip">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-tip" title="Tip"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
We talk about <strong>Provider Contracts</strong> when it is the producer of the API that defines the contracts and
|
||||
publishes it for all its consumers to use. This approach is useful for producers that cannot
|
||||
directly collaborate with their consumers — for example, when there are too many consumers or
|
||||
the consumers are external (do not work within the same company).
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="admonitionblock tip">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-tip" title="Tip"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
We use the term, <strong>Consumer-Driven Contracts</strong>, to refer to workflows where the consumers of an API
|
||||
play a vital role in the process of creating the contracts. We recommended this approach, because it is easy
|
||||
to implement when both producer and consumer teams work for the same organizations and the number
|
||||
of consumers is not extremely large.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="learning-about-spring-cloud-contract-features"><a class="anchor" href="#learning-about-spring-cloud-contract-features"></a><a class="link" href="#learning-about-spring-cloud-contract-features">5. Learning about Spring Cloud Contract Features</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>Need more details about Spring Cloud Contract’s core features?
|
||||
<a href="project-features.html#features">The following content is for you</a>:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><strong>Core Features:</strong>
|
||||
<a href="project-features.html#contract-dsl">Contract DSL</a> |
|
||||
<a href="project-features.html#features-http">Contracts for HTTP</a> |
|
||||
<a href="project-features.html#features-messaging">Contracts for Messaging</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Integrations:</strong>
|
||||
<a href="project-features.html#features-jax-rs">JAX-RS</a> |
|
||||
<a href="project-features.html#features-context-paths">Context Paths</a> |
|
||||
<a href="project-features.html#features-rest-docs">RESTDocs</a>
|
||||
<a href="howto.html#how-to-generate-pact-from-scc">Pact</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Modules:</strong>
|
||||
<a href="project-features.html#features-stub-runner">Stub Runner</a> |
|
||||
<a href="project-features.html#features-wiremock">WireMock</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Build Tools:</strong>
|
||||
<a href="maven-project.html">Contract Verifier - Maven</a> |
|
||||
<a href="gradle-project.html">Contract Verifier - Gradle</a> |
|
||||
<a href="docker-project.html">Docker</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="advanced-topics"><a class="anchor" href="#advanced-topics"></a><a class="link" href="#advanced-topics">6. Advanced Topics</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>Finally, we have a few topics for more advanced users:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><strong>Customizing the DSL:</strong>
|
||||
<a href="advanced.html#contract-dsl-customization">DSL Customization</a> |
|
||||
<a href="advanced.html#contract-dsl-extending-common-jar">Common JAR</a> |
|
||||
<a href="advanced.html#contract-dsl-test-dep">Test Dependency</a> |
|
||||
<a href="advanced.html#contract-dsl-plugin-dep">Plugin Dependency</a> |
|
||||
<a href="advanced.html#contract-dsl-referencing">Referencing the DSL</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Customizing WireMock:</strong>
|
||||
<a href="advanced.html#customization-wiremock-extension">Extensions</a> |
|
||||
<a href="advanced.html#customization-wiremock-configuration">Configuration</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Customizing Spring Cloud Contract:</strong>
|
||||
<a href="advanced.html#contract-dsl-pluggable-architecture">Pluggable Architecture</a> |
|
||||
<a href="advanced.html#contract-dsl-custom-contract-converter">Contract Converter</a> |
|
||||
<a href="advanced.html#contract-dsl-custom-test-generator">Test Generator</a> |
|
||||
<a href="advanced.html#contract-dsl-custom-stub-generator">Stub Generator</a> |
|
||||
<a href="advanced.html#contract-dsl-custom-stub-runner">Stub Runner</a> |
|
||||
<a href="advanced.html#contract-dsl-custom-stub-downloader">Stub Downloader</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</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/github.min.css">
|
||||
<script src="js/highlight/highlight.min.js"></script>
|
||||
<script>hljs.initHighlighting()</script>
|
||||
</body>
|
||||
</html>
|
||||
<title>Page Redirection</title>
|
||||
|
||||
If you are not redirected automatically, follow the <a href='https://spring.io/projects/spring-cloud-contract#learn'>link to docs</a>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,933 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<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.8">
|
||||
<title>Gradle Project</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};
|
||||
}
|
||||
|
||||
function globalSwitch() {
|
||||
$('.switch--item').each(function() {
|
||||
$(this).off('click');
|
||||
$(this).on('click', function() {
|
||||
selectedText = $(this).text()
|
||||
selectedIndex = $(this).index()
|
||||
$(".switch--item").filter(function() { return ($(this).text() === selectedText) }).each(function() {
|
||||
$(this).addClass('selected');
|
||||
$(this).siblings().removeClass('selected');
|
||||
selectedContent = $(this).parent().siblings(".content").eq(selectedIndex)
|
||||
selectedContent.removeClass('hidden');
|
||||
selectedContent.siblings().addClass('hidden');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(addBlockSwitches);
|
||||
$(globalSwitch);
|
||||
<meta http-equiv="refresh" content="1; url=https://spring.io/projects/spring-cloud-contract#learn">
|
||||
|
||||
<script>
|
||||
window.location.href = "https://spring.io/projects/spring-cloud-contract#learn"
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="book toc2 toc-left">
|
||||
<div id="header">
|
||||
<h1>Gradle Project</h1>
|
||||
<div id="toc" class="toc2">
|
||||
<div id="toctitle">Table of Contents</div>
|
||||
<ul class="sectlevel1">
|
||||
<li><a href="#gradle-prerequisites">1. Prerequisites</a></li>
|
||||
<li><a href="#gradle-add-gradle-plugin">2. Add Gradle Plugin with Dependencies</a></li>
|
||||
<li><a href="#gradle-and-rest-assured">3. Gradle and Rest Assured 2.0</a></li>
|
||||
<li><a href="#gradle-snapshot-versions">4. Snapshot Versions for Gradle</a></li>
|
||||
<li><a href="#gradle-add-stubs">5. Add stubs</a></li>
|
||||
<li><a href="#gradle-run-plugin">6. Running the Plugin</a></li>
|
||||
<li><a href="#gradle-default-setup">7. Default Setup</a></li>
|
||||
<li><a href="#gradle-configure-plugin">8. Configuring the Plugin</a></li>
|
||||
<li><a href="#gradle-configuration-options">9. Configuration Options</a></li>
|
||||
<li><a href="#gradle-single-base-class">10. Single Base Class for All Tests</a></li>
|
||||
<li><a href="#gradle-different-base-classes">11. Different Base Classes for Contracts</a>
|
||||
<ul class="sectlevel2">
|
||||
<li><a href="#by-convention">11.1. By Convention</a></li>
|
||||
<li><a href="#by-mapping">11.2. By Mapping</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#gradle-invoking-generated-tests">12. Invoking Generated Tests</a></li>
|
||||
<li><a href="#gradle-pushing-stubs-to-scm">13. Pushing Stubs to SCM</a></li>
|
||||
<li><a href="#gradle-consumer">14. Spring Cloud Contract Verifier on the Consumer Side</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div id="preamble">
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>To learn how to set up the Gradle project for Spring Cloud Contract Verifier, read the
|
||||
following sections:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><a href="#gradle-prerequisites">Prerequisites</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#gradle-add-gradle-plugin">Add Gradle Plugin with Dependencies</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#gradle-and-rest-assured">Gradle and Rest Assured 2.0</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#gradle-snapshot-versions">Snapshot Versions for Gradle</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#gradle-add-stubs">Add stubs</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#gradle-default-setup">Default Setup</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#gradle-configure-plugin">Configuring the Plugin</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#gradle-configuration-options">Configuration Options</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#gradle-single-base-class">Single Base Class for All Tests</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#gradle-different-base-classes">Different Base Classes for Contracts</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#gradle-invoking-generated-tests">Invoking Generated Tests</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#gradle-pushing-stubs-to-scm">Pushing Stubs to SCM</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#gradle-consumer">Spring Cloud Contract Verifier on the Consumer Side</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="gradle-prerequisites"><a class="anchor" href="#gradle-prerequisites"></a><a class="link" href="#gradle-prerequisites">1. Prerequisites</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>In order to use Spring Cloud Contract Verifier with WireMock, you must use either a
|
||||
Gradle or a Maven plugin.</p>
|
||||
</div>
|
||||
<div class="admonitionblock warning">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-warning" title="Warning"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
If you want to use Spock in your projects, you must separately add the
|
||||
<code>spock-core</code> and <code>spock-spring</code> modules. See <a href="https://spockframework.github.io/">Spock’s
|
||||
documnetation for more information</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="gradle-add-gradle-plugin"><a class="anchor" href="#gradle-add-gradle-plugin"></a><a class="link" href="#gradle-add-gradle-plugin">2. Add Gradle Plugin with Dependencies</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>To add a Gradle plugin with dependencies, you can use code similar to the following:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<div class="listingblock primary">
|
||||
<div class="title">Plugin DSL GA versions</div>
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">// build.gradle
|
||||
plugins {
|
||||
id "groovy"
|
||||
// this will work only for GA versions of Spring Cloud Contract
|
||||
id "org.springframework.cloud.contract" version "${GAVerifierVersion}"
|
||||
}
|
||||
<title>Page Redirection</title>
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${GAVerifierVersion}"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile "org.codehaus.groovy:groovy-all:${groovyVersion}"
|
||||
// example with adding Spock core and Spock Spring
|
||||
testCompile "org.spockframework:spock-core:${spockVersion}"
|
||||
testCompile "org.spockframework:spock-spring:${spockVersion}"
|
||||
testCompile 'org.springframework.cloud:spring-cloud-starter-contract-verifier'
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="listingblock secondary">
|
||||
<div class="title">Plugin DSL non GA versions</div>
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">// settings.gradle
|
||||
pluginManagement {
|
||||
plugins {
|
||||
id "org.springframework.cloud.contract" version "${verifierVersion}"
|
||||
}
|
||||
repositories {
|
||||
// to pick from local .m2
|
||||
mavenLocal()
|
||||
// for snapshots
|
||||
maven { url "https://repo.spring.io/snapshot" }
|
||||
// for milestones
|
||||
maven { url "https://repo.spring.io/milestone" }
|
||||
// for GA versions
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
// build.gradle
|
||||
plugins {
|
||||
id "groovy"
|
||||
id "org.springframework.cloud.contract"
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${verifierVersion}"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile "org.codehaus.groovy:groovy-all:${groovyVersion}"
|
||||
// example with adding Spock core and Spock Spring
|
||||
testCompile "org.spockframework:spock-core:${spockVersion}"
|
||||
testCompile "org.spockframework:spock-spring:${spockVersion}"
|
||||
testCompile 'org.springframework.cloud:spring-cloud-starter-contract-verifier'
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="listingblock secondary">
|
||||
<div class="title">Legacy Plugin Application</div>
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">// build.gradle
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springboot_version}"
|
||||
classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifier_version}"
|
||||
// here you can also pass additional dependencies such as Pact or Kotlin spec e.g.:
|
||||
// classpath "org.springframework.cloud:spring-cloud-contract-spec-kotlin:${verifier_version}"
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'groovy'
|
||||
apply plugin: 'spring-cloud-contract'
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${verifier_version}"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile "org.codehaus.groovy:groovy-all:${groovyVersion}"
|
||||
// example with adding Spock core and Spock Spring
|
||||
testCompile "org.spockframework:spock-core:${spockVersion}"
|
||||
testCompile "org.spockframework:spock-spring:${spockVersion}"
|
||||
testCompile 'org.springframework.cloud:spring-cloud-starter-contract-verifier'
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="gradle-and-rest-assured"><a class="anchor" href="#gradle-and-rest-assured"></a><a class="link" href="#gradle-and-rest-assured">3. Gradle and Rest Assured 2.0</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>By default, Rest Assured 3.x is added to the classpath. However, to use Rest Assured 2.x
|
||||
you can add it to the plugins classpath, as the following listing shows:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springboot_version}"
|
||||
classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifier_version}"
|
||||
classpath "com.jayway.restassured:rest-assured:2.5.0"
|
||||
classpath "com.jayway.restassured:spring-mock-mvc:2.5.0"
|
||||
}
|
||||
}
|
||||
|
||||
depenendencies {
|
||||
// all dependencies
|
||||
// you can exclude rest-assured from spring-cloud-contract-verifier
|
||||
testCompile "com.jayway.restassured:rest-assured:2.5.0"
|
||||
testCompile "com.jayway.restassured:spring-mock-mvc:2.5.0"
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>That way, the plugin automatically sees that Rest Assured 2.x is present on the classpath
|
||||
and modifies the imports accordingly.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="gradle-snapshot-versions"><a class="anchor" href="#gradle-snapshot-versions"></a><a class="link" href="#gradle-snapshot-versions">4. Snapshot Versions for Gradle</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>You can add the additional snapshot repository to your <code>build.gradle</code> to use snapshot versions,
|
||||
which are automatically uploaded after every successful build, as the following listing shows:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">/*
|
||||
We need to use the [buildscript {}] section when we have to modify
|
||||
the classpath for the plugins. If that's not the case this section
|
||||
can be skipped.
|
||||
|
||||
If you don't need to modify the classpath (e.g. add a Pact dependency),
|
||||
then you can just set the [pluginManagement {}] section in [settings.gradle] file.
|
||||
|
||||
// settings.gradle
|
||||
pluginManagement {
|
||||
repositories {
|
||||
// for snapshots
|
||||
maven {url "https://repo.spring.io/snapshot"}
|
||||
// for milestones
|
||||
maven {url "https://repo.spring.io/milestone"}
|
||||
// for GA versions
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
maven { url "https://repo.spring.io/snapshot" }
|
||||
maven { url "https://repo.spring.io/milestone" }
|
||||
maven { url "https://repo.spring.io/release" }
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="gradle-add-stubs"><a class="anchor" href="#gradle-add-stubs"></a><a class="link" href="#gradle-add-stubs">5. Add stubs</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>By default, Spring Cloud Contract Verifier looks for stubs in the
|
||||
<code>src/test/resources/contracts</code> directory.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The directory that contains stub definitions is treated as a class name, and each stub
|
||||
definition is treated as a single test. Spring Cloud Contract Verifier assumes that it
|
||||
contains at least one level of directories that are to be used as the test class name.
|
||||
If more than one level of nested directories is present, all except the last one is used
|
||||
as the package name. Consider the following structure:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">src/test/resources/contracts/myservice/shouldCreateUser.groovy
|
||||
src/test/resources/contracts/myservice/shouldReturnUser.groovy</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Given the preceding structure, Spring Cloud Contract Verifier creates a test class named
|
||||
<code>defaultBasePackage.MyService</code> with two methods:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>shouldCreateUser()</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>shouldReturnUser()</code></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="gradle-run-plugin"><a class="anchor" href="#gradle-run-plugin"></a><a class="link" href="#gradle-run-plugin">6. Running the Plugin</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>The plugin registers itself to be invoked before a <code>check</code> task. If you want it to be
|
||||
part of your build process, you need do nothing more. If you just want to generate
|
||||
tests, invoke the <code>generateContractTests</code> task.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="gradle-default-setup"><a class="anchor" href="#gradle-default-setup"></a><a class="link" href="#gradle-default-setup">7. Default Setup</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>The default Gradle Plugin setup creates the following Gradle part of the build (in
|
||||
pseudocode):</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">contracts {
|
||||
testFramework ='JUNIT'
|
||||
testMode = 'MockMvc'
|
||||
generatedTestSourcesDir = project.file("${project.buildDir}/generated-test-sources/contracts")
|
||||
generatedTestResourcesDir = project.file("${project.buildDir}/generated-test-resources/contracts")
|
||||
contractsDslDir = project.file("${project.rootDir}/src/test/resources/contracts")
|
||||
basePackageForTests = 'org.springframework.cloud.verifier.tests'
|
||||
stubsOutputDir = project.file("${project.buildDir}/stubs")
|
||||
sourceSet = null
|
||||
|
||||
// the following properties are used when you want to provide where the JAR with contract lays
|
||||
contractDependency {
|
||||
stringNotation = ''
|
||||
}
|
||||
contractsPath = ''
|
||||
contractsWorkOffline = false
|
||||
contractRepository {
|
||||
cacheDownloadedContracts(true)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.create(type: Jar, name: 'verifierStubsJar', dependsOn: 'generateClientStubs') {
|
||||
baseName = project.name
|
||||
classifier = contracts.stubsSuffix
|
||||
from contractVerifier.stubsOutputDir
|
||||
}
|
||||
|
||||
project.artifacts {
|
||||
archives task
|
||||
}
|
||||
|
||||
tasks.create(type: Copy, name: 'copyContracts') {
|
||||
from contracts.contractsDslDir
|
||||
into contracts.stubsOutputDir
|
||||
}
|
||||
|
||||
verifierStubsJar.dependsOn 'copyContracts'
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
stubs(MavenPublication) {
|
||||
artifactId project.name
|
||||
artifact verifierStubsJar
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="gradle-configure-plugin"><a class="anchor" href="#gradle-configure-plugin"></a><a class="link" href="#gradle-configure-plugin">8. Configuring the Plugin</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>To change the default configuration, you can add a <code>contracts</code> snippet to your Gradle
|
||||
configuration, as the following listing shows:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">contracts {
|
||||
testMode = 'MockMvc'
|
||||
baseClassForTests = 'org.mycompany.tests'
|
||||
generatedTestSourcesDir = project.file('src/generatedContract')
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="gradle-configuration-options"><a class="anchor" href="#gradle-configuration-options"></a><a class="link" href="#gradle-configuration-options">9. Configuration Options</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>testMode</code>: Defines the mode for acceptance tests. By default, the mode is MockMvc,
|
||||
which is based on Spring’s MockMvc. It can also be changed to WebTestClient, JaxRsClient, or
|
||||
Explicit (for real HTTP calls).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>imports</code>: Creates an array with imports that should be included in the generated tests
|
||||
(for example, <code>['org.myorg.Matchers']</code>). By default, it creates an empty array.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>staticImports</code>: Creates an array with static imports that should be included in
|
||||
generated tests(for example, <code>['org.myorg.Matchers.*']</code>). By default, it creates an empty
|
||||
array.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>basePackageForTests</code>: Specifies the base package for all generated tests. If not set,
|
||||
the value is picked from the package of <code>baseClassForTests</code> and from <code>packageWithBaseClasses</code>.
|
||||
If neither of these values are set, the value is set to
|
||||
<code>org.springframework.cloud.contract.verifier.tests</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>baseClassForTests</code>: Creates a base class for all generated tests. By default, if you
|
||||
use Spock classes, the class is <code>spock.lang.Specification</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>packageWithBaseClasses</code>: Defines a package where all the base classes reside. This
|
||||
setting takes precedence over <code>baseClassForTests</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>baseClassMappings</code>: Explicitly maps a contract package to a FQN of a base class. This
|
||||
setting takes precedence over <code>packageWithBaseClasses</code> and <code>baseClassForTests</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>ruleClassForTests</code>: Specifies a rule that should be added to the generated test
|
||||
classes.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>ignoredFiles</code>: Uses an <code>Antmatcher</code> to allow defining stub files for which processing
|
||||
should be skipped. By default, it is an empty array.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>contractsDslDir</code>: Specifies the directory that contains contracts written by using the
|
||||
GroovyDSL. By default, its value is <code>$rootDir/src/test/resources/contracts</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>generatedTestSourcesDir</code>: Specifies the test source directory where tests generated
|
||||
from the Groovy DSL should be placed. By default, its value is
|
||||
<code>$buildDir/generated-test-sources/contracts</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>generatedTestResourcesDir</code>: Specifies the test resource directory where resources used by the tests generated
|
||||
from the Groovy DSL should be placed. By default, its value is
|
||||
<code>$buildDir/generated-test-resources/contracts</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>stubsOutputDir</code>: Specifies the directory where the generated WireMock stubs from
|
||||
the Groovy DSL should be placed.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>testFramework</code>: Specifies the target test framework to be used. Currently, Spock, JUnit 4 (<code>TestFramework.JUNIT</code>), and
|
||||
JUnit 5 are supported, with JUnit 4 being the default framework.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>contractsProperties</code>: A map that contains properties to be passed to Spring Cloud Contract
|
||||
components. Those properties might be used by (for example) built-in or custom Stub Downloaders.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>sourceSet</code>: Source set where the contracts are stored. If not provided will assume <code>test</code> (e.g. <code>project.sourceSets.test.java</code> for JUnit or <code>project.sourceSets.test.groovy</code> for Spock).</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>You can use the following properties when you want to specify the location of the JAR
|
||||
that contains the contracts:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>contractDependency</code>: Specifies the Dependency that provides
|
||||
<code>groupid:artifactid:version:classifier</code> coordinates. You can use the <code>contractDependency</code>
|
||||
closure to set it up.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>contractsPath</code>: Specifies the path to the jar. If contract dependencies are
|
||||
downloaded, the path defaults to <code>groupid/artifactid</code> where <code>groupid</code> is slash
|
||||
separated. Otherwise, it scans contracts under the provided directory.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>contractsMode</code>: Specifies the mode for downloading contracts (whether the
|
||||
JAR is available offline, remotely, and so on).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>deleteStubsAfterTest</code>: If set to <code>false</code>, do not remove any downloaded
|
||||
contracts from temporary directories.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>failOnNoContracts</code>: When enabled, will throw an exception when no contracts were found. Defaults to <code>true</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>failOnInProgress</code>: If set to true then if any contracts that are in progress are found, will break the build. On the producer side you need to be explicit about the fact that you have contracts in progress and take into consideration that you might be causing false positive test execution results on the consumer side.. Defaults to <code>true</code>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>There is also the <code>contractRepository { …​ }</code> closure that contains the following properties</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>repositoryUrl</code>: the URL to the repository with contract definitions</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>username</code> : Repository username</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>password</code> : Repository password</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>proxyPort</code> : the port of the proxy</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>proxyHost</code> : the host of the proxy</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>cacheDownloadedContracts</code> : If set to <code>true</code> then will cache the folder where non snapshot contract artifacts got downloaded. Defaults to <code>true</code>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>You can also turn on the following experimental features in the plugin:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>convertToYaml</code>: Converts all DSLs to the declarative YAML format. This can be extremely
|
||||
useful when you use external libraries in your Groovy DSLs. By turning this feature on
|
||||
(by setting it to <code>true</code>) you need not add the library dependency on the consumer side.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>assertJsonSize</code>: You can check the size of JSON arrays in the generated tests. This
|
||||
feature is disabled by default.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="gradle-single-base-class"><a class="anchor" href="#gradle-single-base-class"></a><a class="link" href="#gradle-single-base-class">10. Single Base Class for All Tests</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>When using Spring Cloud Contract Verifier in default MockMvc, you need to create a base
|
||||
specification for all generated acceptance tests. In this class, you need to point to an
|
||||
endpoint, which should be verified. The following example shows how to do so:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">abstract class BaseMockMvcSpec extends Specification {
|
||||
|
||||
def setup() {
|
||||
RestAssuredMockMvc.standaloneSetup(new PairIdController())
|
||||
}
|
||||
|
||||
void isProperCorrelationId(Integer correlationId) {
|
||||
assert correlationId == 123456
|
||||
}
|
||||
|
||||
void isEmpty(String value) {
|
||||
assert value == null
|
||||
}
|
||||
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>If you use <code>Explicit</code> mode, you can use a base class to initialize the whole tested application,
|
||||
as you might see in regular integration tests. If you use the <code>JAXRSCLIENT</code> mode, this
|
||||
base class should also contain a <code>protected WebTarget webTarget</code> field. Right now, the
|
||||
only option to test the JAX-RS API is to start a web server.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="gradle-different-base-classes"><a class="anchor" href="#gradle-different-base-classes"></a><a class="link" href="#gradle-different-base-classes">11. Different Base Classes for Contracts</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>If your base classes differ between contracts, you can tell the Spring Cloud Contract
|
||||
plugin which class should get extended by the autogenerated tests. You have two options:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>Follow a convention by providing the <code>packageWithBaseClasses</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Provide explicit mapping by using <code>baseClassMappings</code></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="by-convention"><a class="anchor" href="#by-convention"></a><a class="link" href="#by-convention">11.1. By Convention</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>The convention is such that if you have a contract in (for example)
|
||||
<code>src/test/resources/contract/foo/bar/baz/</code> and set the value of the
|
||||
<code>packageWithBaseClasses</code> property to <code>com.example.base</code>, then Spring Cloud Contract
|
||||
Verifier assumes that there is a <code>BarBazBase</code> class under the <code>com.example.base</code> package.
|
||||
In other words, the system takes the last two parts of the package, if they exist, and
|
||||
forms a class with a <code>Base</code> suffix. This rule takes precedence over <code>baseClassForTests</code>.
|
||||
The following example shows how it works in the <code>contracts</code> closure:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">packageWithBaseClasses = 'com.example.base'</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="by-mapping"><a class="anchor" href="#by-mapping"></a><a class="link" href="#by-mapping">11.2. By Mapping</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>You can manually map a regular expression of the contract’s package to the fully qualified
|
||||
name of the base class for the matched contract. You have to provide a list called
|
||||
<code>baseClassMappings</code> that consists of <code>baseClassMapping</code> objects that take a
|
||||
<code>contractPackageRegex</code> to <code>baseClassFQN</code> mapping. Consider the following example:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">baseClassForTests = "com.example.FooBase"
|
||||
baseClassMappings {
|
||||
baseClassMapping('.*/com/.*', 'com.example.ComBase')
|
||||
baseClassMapping('.*/bar/.*': 'com.example.BarBase')
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Let’s assume that you have contracts in the following directories:
|
||||
- <code>src/test/resources/contract/com/</code>
|
||||
- <code>src/test/resources/contract/foo/</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>By providing <code>baseClassForTests</code>, we have a fallback in case mapping did not succeed.
|
||||
(You could also provide the <code>packageWithBaseClasses</code> as a fallback.) That way, the tests
|
||||
generated from <code>src/test/resources/contract/com/</code> contracts extend the
|
||||
<code>com.example.ComBase</code>, whereas the rest of the tests extend <code>com.example.FooBase</code>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="gradle-invoking-generated-tests"><a class="anchor" href="#gradle-invoking-generated-tests"></a><a class="link" href="#gradle-invoking-generated-tests">12. Invoking Generated Tests</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>To ensure that the provider side is compliant with your defined contracts, you need to run
|
||||
the following command:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">./gradlew generateContractTests test</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="gradle-pushing-stubs-to-scm"><a class="anchor" href="#gradle-pushing-stubs-to-scm"></a><a class="link" href="#gradle-pushing-stubs-to-scm">13. Pushing Stubs to SCM</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>If you use the SCM repository to keep the contracts and
|
||||
stubs, you might want to automate the step of pushing stubs to
|
||||
the repository. To do that, you can call the <code>pushStubsToScm</code>
|
||||
task by running the following command:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ ./gradlew pushStubsToScm</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Under <a href="#scm-stub-downloader">[scm-stub-downloader]</a> you can find all possible
|
||||
configuration options that you can pass either through
|
||||
the <code>contractsProperties</code> field (for example, <code>contracts { contractsProperties = [foo:"bar"] }</code>),
|
||||
through the <code>contractsProperties</code> method (for example, <code>contracts { contractsProperties([foo:"bar"]) }</code>),
|
||||
or through a system property or an environment variable.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="gradle-consumer"><a class="anchor" href="#gradle-consumer"></a><a class="link" href="#gradle-consumer">14. Spring Cloud Contract Verifier on the Consumer Side</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>In a consuming service, you need to configure the Spring Cloud Contract Verifier plugin
|
||||
in exactly the same way as in the case of a provider. If you do not want to use Stub Runner,
|
||||
you need to copy the contracts stored in <code>src/test/resources/contracts</code> and generate
|
||||
WireMock JSON stubs by using the following command:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">./gradlew generateClientStubs</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="admonitionblock note">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-note" title="Note"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
The <code>stubsOutputDir</code> option has to be set for stub generation to work.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>When present, JSON stubs can be used in automated tests to consume a service. The
|
||||
following example shows how to do so:</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">@ContextConfiguration(loader == SpringApplicationContextLoader, classes == Application)
|
||||
class LoanApplicationServiceSpec extends Specification {
|
||||
|
||||
@ClassRule
|
||||
@Shared
|
||||
WireMockClassRule wireMockRule == new WireMockClassRule()
|
||||
|
||||
@Autowired
|
||||
LoanApplicationService sut
|
||||
|
||||
def 'should successfully apply for loan'() {
|
||||
given:
|
||||
LoanApplication application =
|
||||
new LoanApplication(client: new Client(clientPesel: '12345678901'), amount: 123.123)
|
||||
when:
|
||||
LoanApplicationResult loanApplication == sut.loanApplication(application)
|
||||
then:
|
||||
loanApplication.loanApplicationStatus == LoanApplicationStatus.LOAN_APPLIED
|
||||
loanApplication.rejectionReason == null
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>In the preceding example, <code>LoanApplication</code> makes a call to the <code>FraudDetection</code> service.
|
||||
This request is handled by a WireMock server configured with stubs that were generated by
|
||||
Spring Cloud Contract Verifier.</p>
|
||||
</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/github.min.css">
|
||||
<script src="js/highlight/highlight.min.js"></script>
|
||||
<script>hljs.initHighlighting()</script>
|
||||
</body>
|
||||
</html>
|
||||
If you are not redirected automatically, follow the <a href='https://spring.io/projects/spring-cloud-contract#learn'>link to docs</a>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,140 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<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.8">
|
||||
<title>Legal</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};
|
||||
}
|
||||
|
||||
function globalSwitch() {
|
||||
$('.switch--item').each(function() {
|
||||
$(this).off('click');
|
||||
$(this).on('click', function() {
|
||||
selectedText = $(this).text()
|
||||
selectedIndex = $(this).index()
|
||||
$(".switch--item").filter(function() { return ($(this).text() === selectedText) }).each(function() {
|
||||
$(this).addClass('selected');
|
||||
$(this).siblings().removeClass('selected');
|
||||
selectedContent = $(this).parent().siblings(".content").eq(selectedIndex)
|
||||
selectedContent.removeClass('hidden');
|
||||
selectedContent.siblings().addClass('hidden');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(addBlockSwitches);
|
||||
$(globalSwitch);
|
||||
<meta http-equiv="refresh" content="1; url=https://spring.io/projects/spring-cloud-contract#learn">
|
||||
|
||||
<script>
|
||||
window.location.href = "https://spring.io/projects/spring-cloud-contract#learn"
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="book">
|
||||
<div id="header">
|
||||
<h1>Legal</h1>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div id="preamble">
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>3.0.0-SNAPSHOT</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Copyright © 2012-2020</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Copies of this document may be made for your own use and for distribution to
|
||||
others, provided that you do not charge any fee for such copies and further
|
||||
provided that each copy contains this Copyright Notice, whether distributed in
|
||||
print or electronically.</p>
|
||||
</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/github.min.css">
|
||||
<script src="js/highlight/highlight.min.js"></script>
|
||||
<script>hljs.initHighlighting()</script>
|
||||
</body>
|
||||
</html>
|
||||
<title>Page Redirection</title>
|
||||
|
||||
If you are not redirected automatically, follow the <a href='https://spring.io/projects/spring-cloud-contract#learn'>link to docs</a>
|
||||
|
||||
@@ -1,137 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<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>Links</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">
|
||||
<meta http-equiv="refresh" content="1; url=https://spring.io/projects/spring-cloud-contract#learn">
|
||||
|
||||
<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>
|
||||
window.location.href = "https://spring.io/projects/spring-cloud-contract#learn"
|
||||
</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="#_links">Links</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div class="sect1">
|
||||
<h2 id="_links"><a class="link" href="#_links">Links</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>The following links may be helpful when working with Spring Cloud Contract:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><a href="https://github.com/spring-cloud/spring-cloud-contract/">Spring Cloud Contract Github
|
||||
Repository</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/">Spring Cloud
|
||||
Contract Samples</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="https://gitter.im/spring-cloud/spring-cloud-contract">Spring Cloud Contract Gitter</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="https://www.youtube.com/watch?v=sAAklvxmPmk">Spring Cloud Contract WJUG Presentation by
|
||||
Marcin Grzejszczak</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</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>
|
||||
<title>Page Redirection</title>
|
||||
|
||||
If you are not redirected automatically, follow the <a href='https://spring.io/projects/spring-cloud-contract#learn'>link to docs</a>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,345 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<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>Migrations</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">
|
||||
<meta http-equiv="refresh" content="1; url=https://spring.io/projects/spring-cloud-contract#learn">
|
||||
|
||||
<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>
|
||||
window.location.href = "https://spring.io/projects/spring-cloud-contract#learn"
|
||||
</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="#_migrations">Migrations</a>
|
||||
<ul class="sectlevel2">
|
||||
<li><a href="#cloud-verifier-1.0-1.1">1.0.x → 1.1.x</a></li>
|
||||
<li><a href="#cloud-verifier-1.1-1.2">1.1.x → 1.2.x</a></li>
|
||||
<li><a href="#cloud-verifier-1.2-2.0">1.2.x → 2.0.x</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div class="sect1">
|
||||
<h2 id="_migrations"><a class="link" href="#_migrations">Migrations</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="admonitionblock tip">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-tip" title="Tip"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
For up to date migration guides please visit
|
||||
the project’s <a href="https://github.com/spring-cloud/spring-cloud-contract/wiki/">wiki page</a>.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>This section covers migrating from one version of Spring Cloud Contract Verifier to the
|
||||
next version. It covers the following versions upgrade paths:</p>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="cloud-verifier-1.0-1.1"><a class="link" href="#cloud-verifier-1.0-1.1">1.0.x → 1.1.x</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>This section covers upgrading from version 1.0 to version 1.1.</p>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="_new_structure_of_generated_stubs"><a class="link" href="#_new_structure_of_generated_stubs">New structure of generated stubs</a></h4>
|
||||
<div class="paragraph">
|
||||
<p>In <code>1.1.x</code> we have introduced a change to the structure of generated stubs. If you have
|
||||
been using the <code>@AutoConfigureWireMock</code> notation to use the stubs from the classpath,
|
||||
it no longer works. The following example shows how the <code>@AutoConfigureWireMock</code> notation
|
||||
used to work:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@AutoConfigureWireMock(stubs = "classpath:/customer-stubs/mappings", port = 8084)</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>You must either change the location of the stubs to:
|
||||
<code>classpath:…​/META-INF/groupId/artifactId/version/mappings</code> or use the new
|
||||
classpath-based <code>@AutoConfigureStubRunner</code>, as shown in the following example:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@AutoConfigureWireMock(stubs = "classpath:customer-stubs/META-INF/travel.components/customer-contract/1.0.2-SNAPSHOT/mappings/", port = 8084)</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>If you do not want to use <code>@AutoConfigureStubRunner</code> and you want to remain with the old
|
||||
structure, set your plugin tasks accordingly. The following example would work for the
|
||||
structure presented in the previous snippet.</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"><!-- start of pom.xml -->
|
||||
<title>Page Redirection</title>
|
||||
|
||||
<properties>
|
||||
<!-- we don't want the verifier to do a jar for us -->
|
||||
<spring.cloud.contract.verifier.skip>true</spring.cloud.contract.verifier.skip>
|
||||
</properties>
|
||||
|
||||
<!-- ... -->
|
||||
|
||||
<!-- You need to set up the assembly plugin -->
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>stub</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<inherited>false</inherited>
|
||||
<configuration>
|
||||
<attach>true</attach>
|
||||
<descriptor>${basedir}/src/assembly/stub.xml</descriptor>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<!-- end of pom.xml -->
|
||||
|
||||
<!-- start of stub.xml-->
|
||||
|
||||
<assembly
|
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 https://maven.apache.org/xsd/assembly-1.1.3.xsd">
|
||||
<id>stubs</id>
|
||||
<formats>
|
||||
<format>jar</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/snippets/stubs</directory>
|
||||
<outputDirectory>customer-stubs/mappings</outputDirectory>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${basedir}/src/test/resources/contracts</directory>
|
||||
<outputDirectory>customer-stubs/contracts</outputDirectory>
|
||||
<includes>
|
||||
<include>**/*.groovy</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
|
||||
<!-- end of 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">task copyStubs(type: Copy, dependsOn: 'generateWireMockClientStubs') {
|
||||
// Preserve directory structure from 1.0.X of spring-cloud-contract
|
||||
from "${project.buildDir}/resources/main/customer-stubs/META-INF/${project.group}/${project.name}/${project.version}"
|
||||
into "${project.buildDir}/resources/main/customer-stubs"
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="cloud-verifier-1.1-1.2"><a class="link" href="#cloud-verifier-1.1-1.2">1.1.x → 1.2.x</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>This section covers upgrading from version 1.1 to version 1.2.</p>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="_custom_httpserverstub"><a class="link" href="#_custom_httpserverstub">Custom <code>HttpServerStub</code></a></h4>
|
||||
<div class="paragraph">
|
||||
<p><code>HttpServerStub</code> includes a method that was not in version 1.1. The method is
|
||||
<code>String registeredMappings()</code> If you have classes that implement <code>HttpServerStub</code>, you
|
||||
now have to implement the <code>registeredMappings()</code> method. It should return a <code>String</code>
|
||||
representing all mappings available in a single <code>HttpServerStub</code>.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>See <a href="https://github.com/spring-cloud/spring-cloud-contract/issues/355">issue 355</a> for more
|
||||
detail.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="_new_packages_for_generated_tests"><a class="link" href="#_new_packages_for_generated_tests">New packages for generated tests</a></h4>
|
||||
<div class="paragraph">
|
||||
<p>The flow for setting the generated tests package name will look like this:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>Set <code>basePackageForTests</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If <code>basePackageForTests</code> was not set, pick the package from <code>baseClassForTests</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If <code>baseClassForTests</code> was not set, pick <code>packageWithBaseClasses</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If nothing got set, pick the default value:
|
||||
<code>org.springframework.cloud.contract.verifier.tests</code></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>See <a href="https://github.com/spring-cloud/spring-cloud-contract/issues/260">issue 260</a> for more
|
||||
detail.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="_new_methods_in_templateprocessor"><a class="link" href="#_new_methods_in_templateprocessor">New Methods in TemplateProcessor</a></h4>
|
||||
<div class="paragraph">
|
||||
<p>In order to add support for <code>fromRequest.path</code>, the following methods had to be added to the
|
||||
<code>TemplateProcessor</code> interface:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>path()</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>path(int index)</code></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>See <a href="https://github.com/spring-cloud/spring-cloud-contract/issues/388">issue 388</a> for more
|
||||
detail.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="_restassured_3_0"><a class="link" href="#_restassured_3_0">RestAssured 3.0</a></h4>
|
||||
<div class="paragraph">
|
||||
<p>Rest Assured, used in the generated test classes, got bumped to <code>3.0</code>. If
|
||||
you manually set versions of Spring Cloud Contract and the release train
|
||||
you might see the following exception:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile (default-testCompile) on project some-project: Compilation failure: Compilation failure:
|
||||
[ERROR] /some/path/SomeClass.java:[4,39] package com.jayway.restassured.response does not exist</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>This exception will occur due to the fact that the tests got generated with
|
||||
an old version of plugin and at test execution time you have an incompatible
|
||||
version of the release train (and vice versa).</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Done via <a href="https://github.com/spring-cloud/spring-cloud-contract/issues/267">issue 267</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="cloud-verifier-1.2-2.0"><a class="link" href="#cloud-verifier-1.2-2.0">1.2.x → 2.0.x</a></h3>
|
||||
|
||||
</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>
|
||||
If you are not redirected automatically, follow the <a href='https://spring.io/projects/spring-cloud-contract#learn'>link to docs</a>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,265 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<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.8">
|
||||
<title>On the Producer Side</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};
|
||||
}
|
||||
|
||||
function globalSwitch() {
|
||||
$('.switch--item').each(function() {
|
||||
$(this).off('click');
|
||||
$(this).on('click', function() {
|
||||
selectedText = $(this).text()
|
||||
selectedIndex = $(this).index()
|
||||
$(".switch--item").filter(function() { return ($(this).text() === selectedText) }).each(function() {
|
||||
$(this).addClass('selected');
|
||||
$(this).siblings().removeClass('selected');
|
||||
selectedContent = $(this).parent().siblings(".content").eq(selectedIndex)
|
||||
selectedContent.removeClass('hidden');
|
||||
selectedContent.siblings().addClass('hidden');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(addBlockSwitches);
|
||||
$(globalSwitch);
|
||||
<meta http-equiv="refresh" content="1; url=https://spring.io/projects/spring-cloud-contract#learn">
|
||||
|
||||
<script>
|
||||
window.location.href = "https://spring.io/projects/spring-cloud-contract#learn"
|
||||
</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="#_on_the_producer_side">On the Producer Side</a></li>
|
||||
<li><a href="#_on_the_consumer_side">On the Consumer Side</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div class="sect1">
|
||||
<h2 id="_on_the_producer_side"><a class="link" href="#_on_the_producer_side">On the Producer Side</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>To start working with Spring Cloud Contract, you can add files with REST or messaging contracts expressed in either Groovy DSL or YAML to the contracts directory, which is set by the contractsDslDir property. By default, it is $rootDir/src/test/resources/contracts.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Then you can add the Spring Cloud Contract Verifier dependency and plugin to your build file, as the following example shows:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"><dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-contract-verifier</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The following listing shows how to add the plugin, which should go in the build/plugins portion of the file:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"><plugin>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
|
||||
<version>${spring-cloud-contract.version}</version>
|
||||
<extensions>true</extensions>
|
||||
</plugin></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Running <code>./mvnw clean install</code> automatically generates tests that verify the application compliance with the added contracts. By default, the tests get generated under <code>org.springframework.cloud.contract.verifier.tests</code>.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>As the implementation of the functionalities described by the contracts is not yet present, the tests fail.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To make them pass, you must add the correct implementation of either handling HTTP requests or messages. Also, you must add a base test class for auto-generated tests to the project. This class is extended by all the auto-generated tests, and it should contain all the setup information necessary to run them (for example <code>RestAssuredMockMvc</code> controller setup or messaging test setup).</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The following example, from pom.xml, shows how to specify the base test class:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"><build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
|
||||
<version>${spring-cloud-contract.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<baseClassForTests>com.example.contractTest.BaseTestClass</baseClassForTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>INFO: The baseClassForTests element lets you specify your base test class. It must be a child of a configuration element within spring-cloud-contract-maven-plugin.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Once the implementation and the test base class are in place, the tests pass, and both the application and the stub artifacts are built and installed in the local Maven repository. You can now merge the changes, and you can publish both the application and the stub artifacts in an online repository.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="_on_the_consumer_side"><a class="link" href="#_on_the_consumer_side">On the Consumer Side</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>You can use Spring Cloud Contract Stub Runner in the integration tests to get a running WireMock instance or messaging route that simulates the actual service.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To do so, add the dependency to Spring Cloud Contract Stub Runner, as the following example shows:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"><dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>You can get the Producer-side stubs installed in your Maven repository in either of two ways:</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>By checking out the Producer side repository and adding contracts and generating the stubs by running the following commands:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ cd local-http-server-repo
|
||||
$ ./mvnw clean install -DskipTests</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The tests are being skipped because the producer-side contract implementation is not in place yet, so the automatically-generated contract tests fail.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>By getting already-existing producer service stubs from a remote repository. To do so, pass the stub artifact IDs and artifact repository URL as Spring Cloud Contract Stub Runner properties, as the following example shows:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-yml hljs" data-lang="yml"> stubrunner:
|
||||
ids: 'com.example:http-server-dsl:+:stubs:8080'
|
||||
repositoryRoot: https://repo.spring.io/libs-snapshot</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Now you can annotate your test class with <code>@AutoConfigureStubRunner</code>. In the annotation, provide the group-id and artifact-id values for Spring Cloud Contract Stub Runner to run the collaborators' stubs for you, as the following example shows:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
|
||||
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
|
||||
stubsMode = StubRunnerProperties.StubsMode.LOCAL)
|
||||
public class LoanApplicationServiceTests {</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Use the <code>REMOTE</code> stubsMode when downloading stubs from an online repository and <code>LOCAL</code> for offline work.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Now, in your integration test, you can receive stubbed versions of HTTP responses or messages that are expected to be emitted by the collaborator service.</p>
|
||||
</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/github.min.css">
|
||||
<script src="js/highlight/highlight.min.js"></script>
|
||||
<script>hljs.initHighlighting()</script>
|
||||
</body>
|
||||
</html>
|
||||
<title>Page Redirection</title>
|
||||
|
||||
If you are not redirected automatically, follow the <a href='https://spring.io/projects/spring-cloud-contract#learn'>link to docs</a>
|
||||
|
||||
@@ -1,266 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<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.8">
|
||||
<title>Features</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};
|
||||
}
|
||||
|
||||
function globalSwitch() {
|
||||
$('.switch--item').each(function() {
|
||||
$(this).off('click');
|
||||
$(this).on('click', function() {
|
||||
selectedText = $(this).text()
|
||||
selectedIndex = $(this).index()
|
||||
$(".switch--item").filter(function() { return ($(this).text() === selectedText) }).each(function() {
|
||||
$(this).addClass('selected');
|
||||
$(this).siblings().removeClass('selected');
|
||||
selectedContent = $(this).parent().siblings(".content").eq(selectedIndex)
|
||||
selectedContent.removeClass('hidden');
|
||||
selectedContent.siblings().addClass('hidden');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(addBlockSwitches);
|
||||
$(globalSwitch);
|
||||
<meta http-equiv="refresh" content="1; url=https://spring.io/projects/spring-cloud-contract#learn">
|
||||
|
||||
<script>
|
||||
window.location.href = "https://spring.io/projects/spring-cloud-contract#learn"
|
||||
</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="#_features">Features</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div id="preamble">
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>Spring Cloud Contract is an umbrella project holding solutions that help users in successfully implementing the Consumer Driven Contracts approach. Currently Spring Cloud Contract consists of the Spring Cloud Contract Verifier project.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Spring Cloud Contract Verifier is a tool that enables Consumer Driven Contract (CDC) development of JVM-based applications. It is shipped with Contract Definition Language (DSL) written in Groovy or YAML. Contract definitions are used to produce following resources:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>by default JSON stub definitions to be used by WireMock (HTTP Server Stub) when doing integration testing on the client code (client tests). Test code must still be written by hand, test data is produced by Spring Cloud Contract Verifier.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Messaging routes if you’re using one. We’re integrating with Spring Integration, Spring Cloud Stream and Apache Camel. You can however set your own integrations if you want to.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Acceptance tests (by default in JUnit or Spock) used to verify if server-side implementation of the API is compliant with the contract (server tests). Full test is generated by Spring Cloud Contract Verifier.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Spring Cloud Contract Verifier moves TDD to the level of software architecture.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To see how Spring Cloud Contract supports other languages just check out <a href="https://spring.io/blog/2018/02/13/spring-cloud-contract-in-a-polyglot-world">this blog post</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="_features"><a class="link" href="#_features">Features</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>When trying to test an application that communicates with other services then we could do one of two things:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>deploy all microservices and perform end to end tests</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>mock other microservices in unit / integration tests</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Both have their advantages but also a lot of disadvantages. Let’s focus on the latter.
|
||||
Deploy all microservices and perform end to end tests</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Advantages:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>simulates production</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>tests real communication between services</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Disadvantages:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>to test one microservice we would have to deploy 6 microservices, a couple of databases etc.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>the environment where the tests would be conducted would be locked for a single suite of tests (i.e. nobody else would be able to run the tests in the meantime).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>long to run</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>very late feedback</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>extremely hard to debug</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Mock other microservices in unit / integration tests</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Advantages:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>very fast feedback</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>no infrastructure requirements</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Disadvantages:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>the implementor of the service creates stubs thus they might have nothing to do with the reality</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>you can go to production with passing tests and failing production</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To solve the aforementioned issues Spring Cloud Contract Verifier with Stub Runner were created. Their main idea is to give you very fast feedback, without the need to set up the whole world of microservices.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Spring Cloud Contract Verifier features:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>ensure that HTTP / Messaging stubs (used when developing the client) are doing exactly what actual server-side implementation will do</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>promote acceptance test driven development method and Microservices architectural style</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>to provide a way to publish changes in contracts that are immediately visible on both sides of the communication</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>to generate boilerplate test code used on the server side</p>
|
||||
</li>
|
||||
</ul>
|
||||
</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/github.min.css">
|
||||
<script src="js/highlight/highlight.min.js"></script>
|
||||
<script>hljs.initHighlighting()</script>
|
||||
</body>
|
||||
</html>
|
||||
<title>Page Redirection</title>
|
||||
|
||||
If you are not redirected automatically, follow the <a href='https://spring.io/projects/spring-cloud-contract#learn'>link to docs</a>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,700 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<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 WireMock</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">
|
||||
<meta http-equiv="refresh" content="1; url=https://spring.io/projects/spring-cloud-contract#learn">
|
||||
|
||||
<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>
|
||||
window.location.href = "https://spring.io/projects/spring-cloud-contract#learn"
|
||||
</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_wiremock">Spring Cloud Contract WireMock</a>
|
||||
<ul class="sectlevel2">
|
||||
<li><a href="#_registering_stubs_automatically">Registering Stubs Automatically</a></li>
|
||||
<li><a href="#_using_files_to_specify_the_stub_bodies">Using Files to Specify the Stub Bodies</a></li>
|
||||
<li><a href="#_alternative_using_junit_rules">Alternative: Using JUnit Rules</a></li>
|
||||
<li><a href="#_relaxed_ssl_validation_for_rest_template">Relaxed SSL Validation for Rest Template</a></li>
|
||||
<li><a href="#_wiremock_and_spring_mvc_mocks">WireMock and Spring MVC Mocks</a></li>
|
||||
<li><a href="#_customization_of_wiremock_configuration">Customization of WireMock configuration</a></li>
|
||||
<li><a href="#_generating_stubs_using_rest_docs">Generating Stubs using REST Docs</a></li>
|
||||
<li><a href="#_generating_contracts_by_using_rest_docs">Generating Contracts by Using REST Docs</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div class="sect1">
|
||||
<h2 id="_spring_cloud_contract_wiremock"><a class="link" href="#_spring_cloud_contract_wiremock">Spring Cloud Contract WireMock</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>The Spring Cloud Contract WireMock modules let you use <a href="https://github.com/tomakehurst/wiremock">WireMock</a> in a
|
||||
Spring Boot application. Check out the
|
||||
<a href="https://github.com/spring-cloud/spring-cloud-contract/tree/{branch}/samples">samples</a>
|
||||
for more details.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>If you have a Spring Boot application that uses Tomcat as an embedded server (which is
|
||||
the default with <code>spring-boot-starter-web</code>), you can add
|
||||
<code>spring-cloud-starter-contract-stub-runner</code> to your classpath and add <code>@AutoConfigureWireMock</code> in
|
||||
order to be able to use Wiremock in your tests. Wiremock runs as a stub server and you
|
||||
can register stub behavior using a Java API or via static JSON declarations as part of
|
||||
your test. The following code shows an example:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureWireMock(port = 0)
|
||||
public class WiremockForDocsTests {
|
||||
<title>Page Redirection</title>
|
||||
|
||||
// A service that calls out over HTTP
|
||||
@Autowired
|
||||
private Service service;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.service.setBase("http://localhost:"
|
||||
+ this.environment.getProperty("wiremock.server.port"));
|
||||
}
|
||||
|
||||
// Using the WireMock APIs in the normal way:
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
// Stubbing WireMock
|
||||
stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
|
||||
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
// We're asserting if WireMock responded properly
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To start the stub server on a different port use (for example),
|
||||
<code>@AutoConfigureWireMock(port=9999)</code>. For a random port, use a value of <code>0</code>. The stub
|
||||
server port can be bound in the test application context with the "wiremock.server.port"
|
||||
property. Using <code>@AutoConfigureWireMock</code> adds a bean of type <code>WiremockConfiguration</code> to
|
||||
your test application context, where it will be cached in between methods and classes
|
||||
having the same context, the same as for Spring integration tests. Also you can inject a bean of type <code>WireMockServer</code> into your test.</p>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_registering_stubs_automatically"><a class="link" href="#_registering_stubs_automatically">Registering Stubs Automatically</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>If you use <code>@AutoConfigureWireMock</code>, it registers WireMock JSON stubs from the file
|
||||
system or classpath (by default, from <code>file:src/test/resources/mappings</code>). You can
|
||||
customize the locations using the <code>stubs</code> attribute in the annotation, which can be an
|
||||
Ant-style resource pattern or a directory. In the case of a directory, <code><strong>*/</strong>.json</code> is
|
||||
appended. The following code shows an example:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre>@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
@AutoConfigureWireMock(stubs="classpath:/stubs")
|
||||
public class WiremockImportApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private Service service;
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="admonitionblock note">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-note" title="Note"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
Actually, WireMock always loads mappings from <code>src/test/resources/mappings</code> <strong>as
|
||||
well as</strong> the custom locations in the stubs attribute. To change this behavior, you can
|
||||
also specify a files root as described in the next section of this document.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>If you’re using Spring Cloud Contract’s default stub jars, then your
|
||||
stubs are stored under <code>/META-INF/group-id/artifact-id/versions/mappings/</code> folder. If you want to register all stubs from that location, from all embedded JARs, then it’s enough to use the following syntax.</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@AutoConfigureWireMock(port = 0, stubs = "classpath*:/META-INF/**/mappings/**/*.json")</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_using_files_to_specify_the_stub_bodies"><a class="link" href="#_using_files_to_specify_the_stub_bodies">Using Files to Specify the Stub Bodies</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>WireMock can read response bodies from files on the classpath or the file system. In that
|
||||
case, you can see in the JSON DSL that the response has a <code>bodyFileName</code> instead of a
|
||||
(literal) <code>body</code>. The files are resolved relative to a root directory (by default,
|
||||
<code>src/test/resources/__files</code>). To customize this location you can set the <code>files</code>
|
||||
attribute in the <code>@AutoConfigureWireMock</code> annotation to the location of the parent
|
||||
directory (in other words, <code>__files</code> is a subdirectory). You can use Spring resource
|
||||
notation to refer to <code>file:…​</code> or <code>classpath:…​</code> locations. Generic URLs are not
|
||||
supported. A list of values can be given, in which case WireMock resolves the first file
|
||||
that exists when it needs to find a response body.</p>
|
||||
</div>
|
||||
<div class="admonitionblock note">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-note" title="Note"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
When you configure the <code>files</code> root, it also affects the
|
||||
automatic loading of stubs, because they come from the root location
|
||||
in a subdirectory called "mappings". The value of <code>files</code> has no
|
||||
effect on the stubs loaded explicitly from the <code>stubs</code> attribute.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_alternative_using_junit_rules"><a class="link" href="#_alternative_using_junit_rules">Alternative: Using JUnit Rules</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>For a more conventional WireMock experience, you can use JUnit <code>@Rules</code> to start and stop
|
||||
the server. To do so, use the <code>WireMockSpring</code> convenience class to obtain an <code>Options</code>
|
||||
instance, as shown in the following example:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class WiremockForDocsClassRuleTests {
|
||||
|
||||
// Start WireMock on some dynamic port
|
||||
// for some reason `dynamicPort()` is not working properly
|
||||
@ClassRule
|
||||
public static WireMockClassRule wiremock = new WireMockClassRule(
|
||||
WireMockSpring.options().dynamicPort());
|
||||
|
||||
// A service that calls out over HTTP to wiremock's port
|
||||
@Autowired
|
||||
private Service service;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.service.setBase("http://localhost:" + wiremock.port());
|
||||
}
|
||||
|
||||
// Using the WireMock APIs in the normal way:
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
// Stubbing WireMock
|
||||
wiremock.stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
|
||||
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
// We're asserting if WireMock responded properly
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The <code>@ClassRule</code> means that the server shuts down after all the methods in this class
|
||||
have been run.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_relaxed_ssl_validation_for_rest_template"><a class="link" href="#_relaxed_ssl_validation_for_rest_template">Relaxed SSL Validation for Rest Template</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>WireMock lets you stub a "secure" server with an "https" URL protocol. If your
|
||||
application wants to contact that stub server in an integration test, it will find that
|
||||
the SSL certificates are not valid (the usual problem with self-installed certificates).
|
||||
The best option is often to re-configure the client to use "http". If that’s not an
|
||||
option, you can ask Spring to configure an HTTP client that ignores SSL validation errors
|
||||
(do so only for tests, of course).</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To make this work with minimum fuss, you need to be using the Spring Boot
|
||||
<code>RestTemplateBuilder</code> in your app, as shown in the following example:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Bean
|
||||
public RestTemplate restTemplate(RestTemplateBuilder builder) {
|
||||
return builder.build();
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>You need <code>RestTemplateBuilder</code> because the builder is passed through callbacks to
|
||||
initialize it, so the SSL validation can be set up in the client at that point. This
|
||||
happens automatically in your test if you are using the <code>@AutoConfigureWireMock</code>
|
||||
annotation or the stub runner. If you use the JUnit <code>@Rule</code> approach, you need to add the
|
||||
<code>@AutoConfigureHttpClient</code> annotation as well, as shown in the following example:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@RunWith(SpringRunner.class)
|
||||
@SpringBootTest("app.baseUrl=https://localhost:6443")
|
||||
@AutoConfigureHttpClient
|
||||
public class WiremockHttpsServerApplicationTests {
|
||||
|
||||
@ClassRule
|
||||
public static WireMockClassRule wiremock = new WireMockClassRule(
|
||||
WireMockSpring.options().httpsPort(6443));
|
||||
...
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>If you are using <code>spring-boot-starter-test</code>, you have the Apache HTTP client on the
|
||||
classpath and it is selected by the <code>RestTemplateBuilder</code> and configured to ignore SSL
|
||||
errors. If you use the default <code>java.net</code> client, you do not need the annotation (but it
|
||||
won’t do any harm). There is no support currently for other clients, but it may be added
|
||||
in future releases.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>To disable the custom <code>RestTemplateBuilder</code>, set the <code>wiremock.rest-template-ssl-enabled</code>
|
||||
property to <code>false</code>.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_wiremock_and_spring_mvc_mocks"><a class="link" href="#_wiremock_and_spring_mvc_mocks">WireMock and Spring MVC Mocks</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>Spring Cloud Contract provides a convenience class that can load JSON WireMock stubs into
|
||||
a Spring <code>MockRestServiceServer</code>. The following code shows an example:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
|
||||
public class WiremockForDocsMockServerApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
@Autowired
|
||||
private Service service;
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
// will read stubs classpath
|
||||
MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate)
|
||||
.baseUrl("https://example.org").stubs("classpath:/stubs/resource.json")
|
||||
.build();
|
||||
// We're asserting if WireMock responded properly
|
||||
assertThat(this.service.go()).isEqualTo("Hello World");
|
||||
server.verify();
|
||||
}
|
||||
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The <code>baseUrl</code> value is prepended to all mock calls, and the <code>stubs()</code> method takes a stub
|
||||
path resource pattern as an argument. In the preceding example, the stub defined at
|
||||
<code>/stubs/resource.json</code> is loaded into the mock server. If the <code>RestTemplate</code> is asked to
|
||||
visit <code><a href="https://example.org/" class="bare">https://example.org/</a></code>, it gets the responses as being declared at that URL. More
|
||||
than one stub pattern can be specified, and each one can be a directory (for a recursive
|
||||
list of all ".json"), a fixed filename (as in the example above), or an Ant-style
|
||||
pattern. The JSON format is the normal WireMock format, which you can read about in the
|
||||
<a href="https://wiremock.org/docs/stubbing/">WireMock website</a>.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Currently, the Spring Cloud Contract Verifier supports Tomcat, Jetty, and Undertow as
|
||||
Spring Boot embedded servers, and Wiremock itself has "native" support for a particular
|
||||
version of Jetty (currently 9.2). To use the native Jetty, you need to add the native
|
||||
Wiremock dependencies and exclude the Spring Boot container (if there is one).</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_customization_of_wiremock_configuration"><a class="link" href="#_customization_of_wiremock_configuration">Customization of WireMock configuration</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>You can register a bean of <code>org.springframework.cloud.contract.wiremock.WireMockConfigurationCustomizer</code> type
|
||||
in order to customize the WireMock configuration (e.g. add custom transformers).
|
||||
Example:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @Bean
|
||||
WireMockConfigurationCustomizer optionsCustomizer() {
|
||||
return new WireMockConfigurationCustomizer() {
|
||||
@Override
|
||||
public void customize(WireMockConfiguration options) {
|
||||
// perform your customization here
|
||||
}
|
||||
};
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_generating_stubs_using_rest_docs"><a class="link" href="#_generating_stubs_using_rest_docs">Generating Stubs using REST Docs</a></h3>
|
||||
<div class="paragraph">
|
||||
<p><a href="https://projects.spring.io/spring-restdocs">Spring REST Docs</a> can be used to generate
|
||||
documentation (for example in Asciidoctor format) for an HTTP API with Spring MockMvc
|
||||
or <code>WebTestClient</code> or Rest Assured. At the same time that you generate documentation for your API, you can also
|
||||
generate WireMock stubs by using Spring Cloud Contract WireMock. To do so, write your
|
||||
normal REST Docs test cases and use <code>@AutoConfigureRestDocs</code> to have stubs be
|
||||
automatically generated in the REST Docs output directory. The following code shows an
|
||||
example using <code>MockMvc</code>:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
@AutoConfigureRestDocs(outputDir = "target/snippets")
|
||||
@AutoConfigureMockMvc
|
||||
public class ApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
mockMvc.perform(get("/resource"))
|
||||
.andExpect(content().string("Hello World"))
|
||||
.andDo(document("resource"));
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>This test generates a WireMock stub at "target/snippets/stubs/resource.json". It matches
|
||||
all GET requests to the "/resource" path. The same example with <code>WebTestClient</code> (used
|
||||
for testing Spring WebFlux applications) would look like this:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
@AutoConfigureRestDocs(outputDir = "target/snippets")
|
||||
@AutoConfigureWebTestClient
|
||||
public class ApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private WebTestClient client;
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
client.get().uri("/resource").exchange()
|
||||
.expectBody(String.class).isEqualTo("Hello World")
|
||||
.consumeWith(document("resource"));
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Without any additional configuration, these tests create a stub with a request matcher
|
||||
for the HTTP method and all headers except "host" and "content-length". To match the
|
||||
request more precisely (for example, to match the body of a POST or PUT), we need to
|
||||
explicitly create a request matcher. Doing so has two effects:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>Creating a stub that matches only in the way you specify.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Asserting that the request in the test case also matches the same conditions.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The main entry point for this feature is <code>WireMockRestDocs.verify()</code>, which can be used
|
||||
as a substitute for the <code>document()</code> convenience method, as shown in the following
|
||||
example:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import static org.springframework.cloud.contract.wiremock.restdocs.WireMockRestDocs.verify;</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre>@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
@AutoConfigureRestDocs(outputDir = "target/snippets")
|
||||
@AutoConfigureMockMvc
|
||||
public class ApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
mockMvc.perform(post("/resource")
|
||||
.content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(verify().jsonPath("$.id")
|
||||
.stub("resource"));
|
||||
}
|
||||
}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>This contract specifies that any valid POST with an "id" field receives the response
|
||||
defined in this test. You can chain together calls to <code>.jsonPath()</code> to add additional
|
||||
matchers. If JSON Path is unfamiliar, The <a href="https://github.com/jayway/JsonPath">JayWay
|
||||
documentation</a> can help you get up to speed. The <code>WebTestClient</code> version of this test
|
||||
has a similar <code>verify()</code> static helper that you insert in the same place.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Instead of the <code>jsonPath</code> and <code>contentType</code> convenience methods, you can also use the
|
||||
WireMock APIs to verify that the request matches the created stub, as shown in the
|
||||
following example:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Test
|
||||
public void contextLoads() throws Exception {
|
||||
mockMvc.perform(post("/resource")
|
||||
.content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(verify()
|
||||
.wiremock(WireMock.post(
|
||||
urlPathEquals("/resource"))
|
||||
.withRequestBody(matchingJsonPath("$.id"))
|
||||
.stub("post-resource"));
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The WireMock API is rich. You can match headers, query parameters, and request body by
|
||||
regex as well as by JSON path. These features can be used to create stubs with a wider
|
||||
range of parameters. The above example generates a stub resembling the following example:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="title">post-resource.json</div>
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-json hljs" data-lang="json">{
|
||||
"request" : {
|
||||
"url" : "/resource",
|
||||
"method" : "POST",
|
||||
"bodyPatterns" : [ {
|
||||
"matchesJsonPath" : "$.id"
|
||||
}]
|
||||
},
|
||||
"response" : {
|
||||
"status" : 200,
|
||||
"body" : "Hello World",
|
||||
"headers" : {
|
||||
"X-Application-Context" : "application:-1",
|
||||
"Content-Type" : "text/plain"
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="admonitionblock note">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-note" title="Note"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
You can use either the <code>wiremock()</code> method or the <code>jsonPath()</code> and <code>contentType()</code>
|
||||
methods to create request matchers, but you can’t use both approaches.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>On the consumer side, you can make the <code>resource.json</code> generated earlier in this section
|
||||
available on the classpath (by
|
||||
<<publishing-stubs-as-jars], for example). After that, you can create a stub using WireMock in a
|
||||
number of different ways, including by using
|
||||
<code>@AutoConfigureWireMock(stubs="classpath:resource.json")</code>, as described earlier in this
|
||||
document.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_generating_contracts_by_using_rest_docs"><a class="link" href="#_generating_contracts_by_using_rest_docs">Generating Contracts by Using REST Docs</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>You can also generate Spring Cloud Contract DSL files and documentation with Spring REST
|
||||
Docs. If you do so in combination with Spring Cloud WireMock, you get both the contracts
|
||||
and the stubs.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Why would you want to use this feature? Some people in the community asked questions
|
||||
about a situation in which they would like to move to DSL-based contract definition,
|
||||
but they already have a lot of Spring MVC tests. Using this feature lets you generate
|
||||
the contract files that you can later modify and move to folders (defined in your
|
||||
configuration) so that the plugin finds them.</p>
|
||||
</div>
|
||||
<div class="admonitionblock tip">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-tip" title="Tip"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
You might wonder why this functionality is in the WireMock module. The functionality
|
||||
is there because it makes sense to generate both the contracts and the stubs.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Consider the following test:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> this.mockMvc
|
||||
.perform(post("/foo").accept(MediaType.APPLICATION_PDF)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"foo\": 23, \"bar\" : \"baz\" }"))
|
||||
.andExpect(status().isOk()).andExpect(content().string("bar"))
|
||||
// first WireMock
|
||||
.andDo(WireMockRestDocs.verify().jsonPath("$[?(@.foo >= 20)]")
|
||||
.jsonPath("$[?(@.bar in ['baz','bazz','bazzz'])]")
|
||||
.contentType(MediaType.valueOf("application/json"))
|
||||
.stub("shouldGrantABeerIfOldEnough"))
|
||||
// then Contract DSL documentation
|
||||
.andDo(document("index", SpringCloudContractRestDocs.dslContract()));</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The preceding test creates the stub presented in the previous section, generating both
|
||||
the contract and a documentation file.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The contract is called <code>index.groovy</code> and might look like the following example:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">import org.springframework.cloud.contract.spec.Contract
|
||||
|
||||
Contract.make {
|
||||
request {
|
||||
method 'POST'
|
||||
url '/foo'
|
||||
body('''
|
||||
{"foo": 23 }
|
||||
''')
|
||||
headers {
|
||||
header('''Accept''', '''application/json''')
|
||||
header('''Content-Type''', '''application/json''')
|
||||
}
|
||||
}
|
||||
response {
|
||||
status OK()
|
||||
body('''
|
||||
bar
|
||||
''')
|
||||
headers {
|
||||
header('''Content-Type''', '''application/json;charset=UTF-8''')
|
||||
header('''Content-Length''', '''3''')
|
||||
}
|
||||
testMatchers {
|
||||
jsonPath('$[?(@.foo >= 20)]', byType())
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The generated document (formatted in Asciidoc in this case) contains a formatted
|
||||
contract. The location of this file would be <code>index/dsl-contract.adoc</code>.</p>
|
||||
</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>
|
||||
If you are not redirected automatically, follow the <a href='https://spring.io/projects/spring-cloud-contract#learn'>link to docs</a>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,401 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<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 Verifier Messaging</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">
|
||||
<meta http-equiv="refresh" content="1; url=https://spring.io/projects/spring-cloud-contract#learn">
|
||||
|
||||
<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>
|
||||
window.location.href = "https://spring.io/projects/spring-cloud-contract#learn"
|
||||
</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_verifier_messaging">Spring Cloud Contract Verifier Messaging</a>
|
||||
<ul class="sectlevel2">
|
||||
<li><a href="#_integrations">Integrations</a></li>
|
||||
<li><a href="#_manual_integration_testing">Manual Integration Testing</a></li>
|
||||
<li><a href="#_publisher_side_test_generation">Publisher-Side Test Generation</a></li>
|
||||
<li><a href="#_consumer_stub_generation">Consumer Stub Generation</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div class="sect1">
|
||||
<h2 id="_spring_cloud_contract_verifier_messaging"><a class="link" href="#_spring_cloud_contract_verifier_messaging">Spring Cloud Contract Verifier Messaging</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>Spring Cloud Contract Verifier lets you verify applications that use messaging as a
|
||||
means of communication. All of the integrations shown in this document work with Spring,
|
||||
but you can also create one of your own and use that.</p>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_integrations"><a class="link" href="#_integrations">Integrations</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>You can use one of the following four integration configurations:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>Apache Camel</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Spring Integration</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Spring Cloud Stream</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Spring AMQP</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Since we use Spring Boot, if you have added one of these libraries to the classpath, all
|
||||
the messaging configuration is automatically set up.</p>
|
||||
</div>
|
||||
<div class="admonitionblock important">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-important" title="Important"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
Remember to put <code>@AutoConfigureMessageVerifier</code> on the base class of your
|
||||
generated tests. Otherwise, messaging part of Spring Cloud Contract Verifier does not
|
||||
work.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</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 to use Spring Cloud Stream, remember to add a dependency on
|
||||
<code>org.springframework.cloud:spring-cloud-stream-test-support</code>, as shown here:
|
||||
</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"><dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-stream-test-support</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency></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">testCompile "org.springframework.cloud:spring-cloud-stream-test-support"</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_manual_integration_testing"><a class="link" href="#_manual_integration_testing">Manual Integration Testing</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>The main interface used by the tests is
|
||||
<code>org.springframework.cloud.contract.verifier.messaging.MessageVerifier</code>.
|
||||
It defines how to send and receive messages. You can create your own implementation to
|
||||
achieve the same goal.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>In a test, you can inject a <code>ContractVerifierMessageExchange</code> to send and receive
|
||||
messages that follow the contract. Then add <code>@AutoConfigureMessageVerifier</code> to your test.
|
||||
Here’s an example:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@RunWith(SpringTestRunner.class)
|
||||
@SpringBootTest
|
||||
@AutoConfigureMessageVerifier
|
||||
public static class MessagingContractTests {
|
||||
<title>Page Redirection</title>
|
||||
|
||||
@Autowired
|
||||
private MessageVerifier verifier;
|
||||
...
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="admonitionblock note">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-note" title="Note"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
If your tests require stubs as well, then <code>@AutoConfigureStubRunner</code> includes the
|
||||
messaging configuration, so you only need the one annotation.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_publisher_side_test_generation"><a class="link" href="#_publisher_side_test_generation">Publisher-Side Test Generation</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>Having the <code>input</code> or <code>outputMessage</code> sections in your DSL results in creation of tests
|
||||
on the publisher’s side. By default, JUnit 4 tests are created. However, there is also a
|
||||
possibility to create JUnit 5, TestNG or Spock tests.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>There are 3 main scenarios that we should take into consideration:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>Scenario 1: There is no input message that produces an output message. The output
|
||||
message is triggered by a component inside the application (for example, scheduler).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Scenario 2: The input message triggers an output message.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Scenario 3: The input message is consumed and there is no output message.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="admonitionblock important">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-important" title="Important"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
The destination passed to <code>messageFrom</code> or <code>sentTo</code> can have different
|
||||
meanings for different messaging implementations. For <strong>Stream</strong> and <strong>Integration</strong> it is
|
||||
first resolved as a <code>destination</code> of a channel. Then, if there is no such <code>destination</code>
|
||||
it is resolved as a channel name. For <strong>Camel</strong>, that’s a certain component (for example,
|
||||
<code>jms</code>).
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="_scenario_1_no_input_message"><a class="link" href="#_scenario_1_no_input_message">Scenario 1: No Input Message</a></h4>
|
||||
<div class="paragraph">
|
||||
<p>For the given contract:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Groovy DSL</div>
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="title">YAML</div>
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-yml hljs" data-lang="yml"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The following JUnit test is created:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>And the following Spock test would be created:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="_scenario_2_output_triggered_by_input"><a class="link" href="#_scenario_2_output_triggered_by_input">Scenario 2: Output Triggered by Input</a></h4>
|
||||
<div class="paragraph">
|
||||
<p>For the given contract:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Groovy DSL</div>
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="title">YAML</div>
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-yml hljs" data-lang="yml"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The following JUnit test is created:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>And the following Spock test would be created:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="_scenario_3_no_output_message"><a class="link" href="#_scenario_3_no_output_message">Scenario 3: No Output Message</a></h4>
|
||||
<div class="paragraph">
|
||||
<p>For the given contract:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Groovy DSL</div>
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="title">YAML</div>
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-yml hljs" data-lang="yml"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The following JUnit test is created:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>And the following Spock test would be created:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_consumer_stub_generation"><a class="link" href="#_consumer_stub_generation">Consumer Stub Generation</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>Unlike the HTTP part, in messaging, we need to publish the Groovy DSL inside the JAR with
|
||||
a stub. Then it is parsed on the consumer side and proper stubbed routes are created.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>For more information, see <a href="#stub-runner-for-messaging">[stub-runner-for-messaging]</a> section.</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>
|
||||
</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>
|
||||
If you are not redirected automatically, follow the <a href='https://spring.io/projects/spring-cloud-contract#learn'>link to docs</a>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,431 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<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">
|
||||
<meta http-equiv="refresh" content="1; url=https://spring.io/projects/spring-cloud-contract#learn">
|
||||
|
||||
<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>
|
||||
window.location.href = "https://spring.io/projects/spring-cloud-contract#learn"
|
||||
</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 -->
|
||||
<title>Page Redirection</title>
|
||||
|
||||
<!-- 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>
|
||||
If you are not redirected automatically, follow the <a href='https://spring.io/projects/spring-cloud-contract#learn'>link to docs</a>
|
||||
|
||||
@@ -1,223 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<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>Stub Runner for Messaging</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">
|
||||
<meta http-equiv="refresh" content="1; url=https://spring.io/projects/spring-cloud-contract#learn">
|
||||
|
||||
<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>
|
||||
window.location.href = "https://spring.io/projects/spring-cloud-contract#learn"
|
||||
</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="#stub-runner-for-messaging">Stub Runner for Messaging</a>
|
||||
<ul class="sectlevel2">
|
||||
<li><a href="#_stub_triggering">Stub triggering</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div class="sect1">
|
||||
<h2 id="stub-runner-for-messaging"><a class="link" href="#stub-runner-for-messaging">Stub Runner for Messaging</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>Stub Runner can run the published stubs in memory. It can integrate with the following
|
||||
frameworks:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>Spring Integration</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Spring Cloud Stream</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Apache Camel</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Spring AMQP</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>It also provides entry points to integrate with any other solution on the market.</p>
|
||||
</div>
|
||||
<div class="admonitionblock important">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-important" title="Important"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
If you have multiple frameworks on the classpath Stub Runner will need to
|
||||
define which one should be used. Let’s assume that you have both AMQP, Spring Cloud Stream and Spring Integration
|
||||
on the classpath. Then you need to set <code>stubrunner.stream.enabled=false</code> and <code>stubrunner.integration.enabled=false</code>.
|
||||
That way the only remaining framework is Spring AMQP.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_stub_triggering"><a class="link" href="#_stub_triggering">Stub triggering</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>To trigger a message, use the <code>StubTrigger</code> interface:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>For convenience, the <code>StubFinder</code> interface extends <code>StubTrigger</code>, so you only need one
|
||||
or the other in your tests.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>StubTrigger</code> gives you the following options to trigger a message:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><a href="#trigger-label">Trigger by Label</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#trigger-group-artifact-ids">Trigger by Group and Artifact Ids</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#trigger-artifact-ids">Trigger by Artifact Ids</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#trigger-all-messages">Trigger All Messages</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="trigger-label"><a class="link" href="#trigger-label">Trigger by Label</a></h4>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="trigger-group-artifact-ids"><a class="link" href="#trigger-group-artifact-ids">Trigger by Group and Artifact Ids</a></h4>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="trigger-artifact-ids"><a class="link" href="#trigger-artifact-ids">Trigger by Artifact Ids</a></h4>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="trigger-all-messages"><a class="link" href="#trigger-all-messages">Trigger All Messages</a></h4>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
||||
</div>
|
||||
</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>
|
||||
<title>Page Redirection</title>
|
||||
|
||||
If you are not redirected automatically, follow the <a href='https://spring.io/projects/spring-cloud-contract#learn'>link to docs</a>
|
||||
|
||||
@@ -1,592 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<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.8">
|
||||
<title>YML Schema</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};
|
||||
}
|
||||
|
||||
function globalSwitch() {
|
||||
$('.switch--item').each(function() {
|
||||
$(this).off('click');
|
||||
$(this).on('click', function() {
|
||||
selectedText = $(this).text()
|
||||
selectedIndex = $(this).index()
|
||||
$(".switch--item").filter(function() { return ($(this).text() === selectedText) }).each(function() {
|
||||
$(this).addClass('selected');
|
||||
$(this).siblings().removeClass('selected');
|
||||
selectedContent = $(this).parent().siblings(".content").eq(selectedIndex)
|
||||
selectedContent.removeClass('hidden');
|
||||
selectedContent.siblings().addClass('hidden');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(addBlockSwitches);
|
||||
$(globalSwitch);
|
||||
<meta http-equiv="refresh" content="1; url=https://spring.io/projects/spring-cloud-contract#learn">
|
||||
|
||||
<script>
|
||||
window.location.href = "https://spring.io/projects/spring-cloud-contract#learn"
|
||||
</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="#yml-schema">YML Schema</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div class="sect1">
|
||||
<h2 id="yml-schema"><a class="link" href="#yml-schema">YML Schema</a></h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>Below you can find a JSON schema definition of a YAML contract.</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre class="highlightjs highlight"><code class="language-json hljs" data-lang="json">{
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract",
|
||||
"properties" : {
|
||||
"request" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:Request",
|
||||
"properties" : {
|
||||
"method" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"url" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"urlPath" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"queryParameters" : {
|
||||
"type" : "object",
|
||||
"additionalProperties" : {
|
||||
"type" : "any"
|
||||
}
|
||||
},
|
||||
"headers" : {
|
||||
"type" : "object",
|
||||
"additionalProperties" : {
|
||||
"type" : "any"
|
||||
}
|
||||
},
|
||||
"cookies" : {
|
||||
"type" : "object",
|
||||
"additionalProperties" : {
|
||||
"type" : "any"
|
||||
}
|
||||
},
|
||||
"body" : {
|
||||
"type" : "any"
|
||||
},
|
||||
"bodyFromFile" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"bodyFromFileAsBytes" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"matchers" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:StubMatchers",
|
||||
"properties" : {
|
||||
"url" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:KeyValueMatcher",
|
||||
"properties" : {
|
||||
"key" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"regex" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"predefined" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "only_alpha_unicode", "number", "any_double", "any_boolean", "ip_address", "hostname", "email", "url", "uuid", "iso_date", "iso_date_time", "iso_time", "iso_8601_with_offset", "non_empty", "non_blank" ]
|
||||
},
|
||||
"command" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"regexType" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "as_integer", "as_double", "as_float", "as_long", "as_short", "as_boolean", "as_string" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
"body" : {
|
||||
"type" : "array",
|
||||
"items" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:BodyStubMatcher",
|
||||
"properties" : {
|
||||
"path" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"type" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "by_date", "by_time", "by_timestamp", "by_regex", "by_equality", "by_type", "by_null" ]
|
||||
},
|
||||
"value" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"predefined" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "only_alpha_unicode", "number", "any_double", "any_boolean", "ip_address", "hostname", "email", "url", "uuid", "iso_date", "iso_date_time", "iso_time", "iso_8601_with_offset", "non_empty", "non_blank" ]
|
||||
},
|
||||
"minOccurrence" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"maxOccurrence" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"regexType" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "as_integer", "as_double", "as_float", "as_long", "as_short", "as_boolean", "as_string" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"headers" : {
|
||||
"type" : "array",
|
||||
"items" : {
|
||||
"type" : "object",
|
||||
"$ref" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:KeyValueMatcher"
|
||||
}
|
||||
},
|
||||
"queryParameters" : {
|
||||
"type" : "array",
|
||||
"items" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:QueryParameterMatcher",
|
||||
"properties" : {
|
||||
"key" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"type" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "equal_to", "containing", "matching", "not_matching", "equal_to_json", "equal_to_xml", "absent", "binary_equal_to" ]
|
||||
},
|
||||
"value" : {
|
||||
"type" : "any"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cookies" : {
|
||||
"type" : "array",
|
||||
"items" : {
|
||||
"type" : "object",
|
||||
"$ref" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:KeyValueMatcher"
|
||||
}
|
||||
},
|
||||
"multipart" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:MultipartStubMatcher",
|
||||
"properties" : {
|
||||
"params" : {
|
||||
"type" : "array",
|
||||
"items" : {
|
||||
"type" : "object",
|
||||
"$ref" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:KeyValueMatcher"
|
||||
}
|
||||
},
|
||||
"named" : {
|
||||
"type" : "array",
|
||||
"items" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:MultipartNamedStubMatcher",
|
||||
"properties" : {
|
||||
"paramName" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"fileName" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:ValueMatcher",
|
||||
"properties" : {
|
||||
"regex" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"predefined" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "only_alpha_unicode", "number", "any_double", "any_boolean", "ip_address", "hostname", "email", "url", "uuid", "iso_date", "iso_date_time", "iso_time", "iso_8601_with_offset", "non_empty", "non_blank" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
"fileContent" : {
|
||||
"type" : "object",
|
||||
"$ref" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:ValueMatcher"
|
||||
},
|
||||
"contentType" : {
|
||||
"type" : "object",
|
||||
"$ref" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:ValueMatcher"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"multipart" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:Multipart",
|
||||
"properties" : {
|
||||
"params" : {
|
||||
"type" : "object",
|
||||
"additionalProperties" : {
|
||||
"type" : "string"
|
||||
}
|
||||
},
|
||||
"named" : {
|
||||
"type" : "array",
|
||||
"items" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:Named",
|
||||
"properties" : {
|
||||
"paramName" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"fileName" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"fileContent" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"fileContentAsBytes" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"fileContentFromFileAsBytes" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"contentType" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"fileNameCommand" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"fileContentCommand" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"contentTypeCommand" : {
|
||||
"type" : "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"response" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:Response",
|
||||
"properties" : {
|
||||
"status" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"headers" : {
|
||||
"type" : "object",
|
||||
"additionalProperties" : {
|
||||
"type" : "any"
|
||||
}
|
||||
},
|
||||
"cookies" : {
|
||||
"type" : "object",
|
||||
"additionalProperties" : {
|
||||
"type" : "any"
|
||||
}
|
||||
},
|
||||
"body" : {
|
||||
"type" : "any"
|
||||
},
|
||||
"bodyFromFile" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"bodyFromFileAsBytes" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"matchers" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:TestMatchers",
|
||||
"properties" : {
|
||||
"body" : {
|
||||
"type" : "array",
|
||||
"items" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:BodyTestMatcher",
|
||||
"properties" : {
|
||||
"path" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"type" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "by_date", "by_time", "by_timestamp", "by_regex", "by_equality", "by_type", "by_command", "by_null" ]
|
||||
},
|
||||
"value" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"minOccurrence" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"maxOccurrence" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"predefined" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "only_alpha_unicode", "number", "any_double", "any_boolean", "ip_address", "hostname", "email", "url", "uuid", "iso_date", "iso_date_time", "iso_time", "iso_8601_with_offset", "non_empty", "non_blank" ]
|
||||
},
|
||||
"regexType" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "as_integer", "as_double", "as_float", "as_long", "as_short", "as_boolean", "as_string" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"headers" : {
|
||||
"type" : "array",
|
||||
"items" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:TestHeaderMatcher",
|
||||
"properties" : {
|
||||
"key" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"regex" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"command" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"predefined" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "only_alpha_unicode", "number", "any_double", "any_boolean", "ip_address", "hostname", "email", "url", "uuid", "iso_date", "iso_date_time", "iso_time", "iso_8601_with_offset", "non_empty", "non_blank" ]
|
||||
},
|
||||
"regexType" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "as_integer", "as_double", "as_float", "as_long", "as_short", "as_boolean", "as_string" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cookies" : {
|
||||
"type" : "array",
|
||||
"items" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:TestCookieMatcher",
|
||||
"properties" : {
|
||||
"key" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"regex" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"command" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"predefined" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "only_alpha_unicode", "number", "any_double", "any_boolean", "ip_address", "hostname", "email", "url", "uuid", "iso_date", "iso_date_time", "iso_time", "iso_8601_with_offset", "non_empty", "non_blank" ]
|
||||
},
|
||||
"regexType" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "as_integer", "as_double", "as_float", "as_long", "as_short", "as_boolean", "as_string" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"async" : {
|
||||
"type" : "boolean"
|
||||
},
|
||||
"fixedDelayMilliseconds" : {
|
||||
"type" : "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"input" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:Input",
|
||||
"properties" : {
|
||||
"messageFrom" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"triggeredBy" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"messageHeaders" : {
|
||||
"type" : "object",
|
||||
"additionalProperties" : {
|
||||
"type" : "any"
|
||||
}
|
||||
},
|
||||
"messageBody" : {
|
||||
"type" : "any"
|
||||
},
|
||||
"messageBodyFromFile" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"messageBodyFromFileAsBytes" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"assertThat" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"matchers" : {
|
||||
"type" : "object",
|
||||
"$ref" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:StubMatchers"
|
||||
}
|
||||
}
|
||||
},
|
||||
"outputMessage" : {
|
||||
"type" : "object",
|
||||
"id" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:OutputMessage",
|
||||
"properties" : {
|
||||
"sentTo" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"headers" : {
|
||||
"type" : "object",
|
||||
"additionalProperties" : {
|
||||
"type" : "any"
|
||||
}
|
||||
},
|
||||
"body" : {
|
||||
"type" : "any"
|
||||
},
|
||||
"bodyFromFile" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"bodyFromFileAsBytes" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"assertThat" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"matchers" : {
|
||||
"type" : "object",
|
||||
"$ref" : "urn:jsonschema:org:springframework:cloud:contract:verifier:converter:YamlContract:TestMatchers"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"label" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"name" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"priority" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"ignored" : {
|
||||
"type" : "boolean"
|
||||
},
|
||||
"inProgress" : {
|
||||
"type" : "boolean"
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</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/github.min.css">
|
||||
<script src="js/highlight/highlight.min.js"></script>
|
||||
<script>hljs.initHighlighting()</script>
|
||||
</body>
|
||||
</html>
|
||||
<title>Page Redirection</title>
|
||||
|
||||
If you are not redirected automatically, follow the <a href='https://spring.io/projects/spring-cloud-contract#learn'>link to docs</a>
|
||||
|
||||
Reference in New Issue
Block a user