Sync docs from 2.0.x to gh-pages
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>9. Customization</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud-contract.html" title="Spring Cloud Contract"><link rel="up" href="multi_spring-cloud-contract.html" title="Spring Cloud Contract"><link rel="prev" href="multi__contract_dsl.html" title="8. Contract DSL"><link rel="next" href="multi__using_the_pluggable_architecture.html" title="10. Using the Pluggable Architecture"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9. Customization</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__contract_dsl.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi__using_the_pluggable_architecture.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_customization" href="#_customization"></a>9. Customization</h1></div></div></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>This section is valid only for Groovy DSL</p></td></tr></table></div><p>You can customize the Spring Cloud Contract Verifier by extending the DSL, as shown in
|
||||
<title>9. Customization</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud-contract.html" title="Spring Cloud Contract"><link rel="up" href="multi_spring-cloud-contract.html" title="Spring Cloud Contract"><link rel="prev" href="multi_contract-dsl.html" title="8. Contract DSL"><link rel="next" href="multi__using_the_pluggable_architecture.html" title="10. Using the Pluggable Architecture"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9. Customization</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_contract-dsl.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi__using_the_pluggable_architecture.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_customization" href="#_customization"></a>9. Customization</h1></div></div></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>This section is valid only for Groovy DSL</p></td></tr></table></div><p>You can customize the Spring Cloud Contract Verifier by extending the DSL, as shown in
|
||||
the remainder of this section.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_extending_the_dsl" href="#_extending_the_dsl"></a>9.1 Extending the DSL</h2></div></div></div><p>You can provide your own functions to the DSL. The key requirement for this feature is to
|
||||
maintain the static compatibility. Later in this document, you can see examples of:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Creating a JAR with reusable classes.</li><li class="listitem">Referencing of these classes in the DSLs.</li></ul></div><p>You can find the full example
|
||||
<a class="link" href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples" target="_top">here</a>.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_common_jar" href="#_common_jar"></a>9.1.1 Common JAR</h3></div></div></div><p>The following examples show three classes that can be reused in the DSLs.</p><p><span class="strong"><strong>PatternUtils</strong></span> contains functions used by both the <span class="strong"><strong>consumer</strong></span> and the <span class="strong"><strong>producer</strong></span>.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> com.example;
|
||||
@@ -214,4 +214,4 @@ then:
|
||||
contentType(applicationJson())
|
||||
}
|
||||
}
|
||||
}</pre></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__contract_dsl.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="multi__using_the_pluggable_architecture.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">8. Contract DSL </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud-contract.html">Home</a></td><td width="40%" align="right" valign="top"> 10. Using the Pluggable Architecture</td></tr></table></div></body></html>
|
||||
}</pre></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_contract-dsl.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="multi__using_the_pluggable_architecture.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">8. Contract DSL </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud-contract.html">Home</a></td><td width="40%" align="right" valign="top"> 10. Using the Pluggable Architecture</td></tr></table></div></body></html>
|
||||
@@ -45,7 +45,7 @@ sides of the communication. You can pass the values:</p><p>Either via the <code
|
||||
value(stub(...), test(...))
|
||||
value(client(...), server(...))</pre><p>or using the <code class="literal">$()</code> method</p><pre class="programlisting">$(consumer(...), producer(...))
|
||||
$(stub(...), test(...))
|
||||
$(client(...), server(...))</pre><p>You can read more about this in the <a class="xref" href="">???</a> section.</p><p>Calling <code class="literal">value()</code> or <code class="literal">$()</code> tells Spring Cloud Contract that you will be passing a dynamic value.
|
||||
$(client(...), server(...))</pre><p>You can read more about this in the <a class="xref" href="multi_contract-dsl.html" title="8. Contract DSL">Chapter 8, <i>Contract DSL</i></a> section.</p><p>Calling <code class="literal">value()</code> or <code class="literal">$()</code> tells Spring Cloud Contract that you will be passing a dynamic value.
|
||||
Inside the <code class="literal">consumer()</code> method you pass the value that should be used on the consumer side (in the generated stub).
|
||||
Inside the <code class="literal">producer()</code> method you pass the value that should be used on the producer side (in the generated test).</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>If on one side you have passed the regular expression and you haven’t passed the other, then the
|
||||
other side will get auto-generated.</p></td></tr></table></div><p>Most often you will use that method together with the <code class="literal">regex</code> helper method. E.g. <code class="literal">consumer(regex('[0-9]{10}'))</code>.</p><p>To sum it up the contract for the aforementioned scenario would look more or less like this (the regular expression
|
||||
@@ -82,7 +82,7 @@ It can be related to security issues where the consumers can’t clone the p
|
||||
contracts in a single place then you, as a producer, will know how many consumers you have and which
|
||||
consumer will you break with your local changes.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_repo_structure" href="#_repo_structure"></a>3.5.1 Repo structure</h3></div></div></div><p>Let’s assume that we have a producer with coordinates <code class="literal">com.example:server</code> and 3 consumers: <code class="literal">client1</code>,
|
||||
<code class="literal">client2</code>, <code class="literal">client3</code>. Then in the repository with common contracts you would have the following setup
|
||||
(which you can checkout <a class="link" href="https://github.com/spring-cloud/spring-cloud-contract/tree/master/samples/standalone/contracts" target="_top">here</a>):</p><pre class="programlisting">├── com
|
||||
(which you can checkout <a class="link" href="https://github.com/spring-cloud/spring-cloud-contract/tree/2.0.x/samples/standalone/contracts" target="_top">here</a>):</p><pre class="programlisting">├── com
|
||||
│ └── example
|
||||
│ └── server
|
||||
│ ├── client1
|
||||
@@ -115,14 +115,14 @@ one to one to the contents of the repo.</p><p>Example of a <code class="literal"
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><parent></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.boot<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-boot-starter-parent<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>2.0.3.RELEASE<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>2.0.4.RELEASE<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><relativePath /></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></parent></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><properties></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><project.build.sourceEncoding></span>UTF-8<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></project.build.sourceEncoding></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><java.version></span>1.8<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></java.version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><spring-cloud-contract.version></span>2.1.0.BUILD-SNAPSHOT<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></spring-cloud-contract.version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><spring-cloud-contract.version></span>2.0.2.BUILD-SNAPSHOT<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></spring-cloud-contract.version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><spring-cloud-release.version></span>Finchley.BUILD-SNAPSHOT<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></spring-cloud-release.version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><excludeBuildFolders></span>true<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></excludeBuildFolders></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></properties></span>
|
||||
@@ -399,7 +399,7 @@ build.dependsOn(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">
|
||||
Artifactory or Nexus. Starting from Spring Cloud Contract version 2.0.0 we provide
|
||||
mechanisms to store contracts and stubs in a SCM repository. Currently the
|
||||
only supported SCM is Git.</p><p>The repository would have to the following setup
|
||||
(which you can checkout <a class="link" href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/2.0.x/contracts_git/" target="_top">here</a>):</p><pre class="screen">.
|
||||
(which you can checkout <a class="link" href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/master/contracts_git/" target="_top">here</a>):</p><pre class="screen">.
|
||||
└── META-INF
|
||||
└── com.example
|
||||
└── beer-api-producer-git
|
||||
@@ -515,11 +515,11 @@ shares the files with the Producer. Those expectations are generated
|
||||
from the Consumer’s code and can break the Producer if the expectation
|
||||
is not met.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_pact_consumer" href="#_pact_consumer"></a>3.7.1 Pact Consumer</h3></div></div></div><p>The consumer uses Pact framework to generate Pact files. The
|
||||
Pact files are sent to the Pact Broker. An example of such
|
||||
setup can be found <a class="link" href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/2.0.x/consumer_pact" target="_top">here</a>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_producer_3" href="#_producer_3"></a>3.7.2 Producer</h3></div></div></div><p>For the producer, to use the Pact files from the Pact Broker, we can reuse the
|
||||
setup can be found <a class="link" href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/master/consumer_pact" target="_top">here</a>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_producer_3" href="#_producer_3"></a>3.7.2 Producer</h3></div></div></div><p>For the producer, to use the Pact files from the Pact Broker, we can reuse the
|
||||
same mechanism we use for external contracts. We route Spring Cloud Contract
|
||||
to use the Pact implementation via the URL that contains
|
||||
the <code class="literal">pact://</code> protocol. It’s enough to pass the URL to the
|
||||
Pact Broker. An example of such setup can be found <a class="link" href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/2.0.x/producer_pact" target="_top">here</a>.</p><p><b>Maven. </b>
|
||||
Pact Broker. An example of such setup can be found <a class="link" href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/master/producer_pact" target="_top">here</a>.</p><p><b>Maven. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><plugin></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-contract-maven-plugin<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
@@ -582,7 +582,7 @@ contracts {
|
||||
(for every single consumer define the expectations) but you’d prefer
|
||||
to do Producer Contracts (the producer provides the contracts and
|
||||
publishes stubs), it’s enough to use Spring Cloud Contract with
|
||||
Stub Runner option. An example of such setup can be found <a class="link" href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/2.0.x/consumer_pact_stubrunner" target="_top">here</a>.</p><p>First, remember to add Stub Runner and Spring Cloud Contract Pact module
|
||||
Stub Runner option. An example of such setup can be found <a class="link" href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/master/consumer_pact_stubrunner" target="_top">here</a>.</p><p>First, remember to add Stub Runner and Spring Cloud Contract Pact module
|
||||
as test dependencies.</p><p><b>Maven. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencyManagement></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencies></span>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>6. Spring Cloud Contract Stub Runner</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud-contract.html" title="Spring Cloud Contract"><link rel="up" href="multi_spring-cloud-contract.html" title="Spring Cloud Contract"><link rel="prev" href="multi__spring_cloud_contract_verifier_messaging.html" title="5. Spring Cloud Contract Verifier Messaging"><link rel="next" href="multi__stub_runner_for_messaging.html" title="7. Stub Runner for Messaging"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">6. Spring Cloud Contract Stub Runner</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_contract_verifier_messaging.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi__stub_runner_for_messaging.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_spring_cloud_contract_stub_runner" href="#_spring_cloud_contract_stub_runner"></a>6. Spring Cloud Contract Stub Runner</h1></div></div></div><p>One of the issues that you might encounter while using Spring Cloud Contract Verifier is
|
||||
<title>6. Spring Cloud Contract Stub Runner</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud-contract.html" title="Spring Cloud Contract"><link rel="up" href="multi_spring-cloud-contract.html" title="Spring Cloud Contract"><link rel="prev" href="multi__spring_cloud_contract_verifier_messaging.html" title="5. Spring Cloud Contract Verifier Messaging"><link rel="next" href="multi_stub-runner-for-messaging.html" title="7. Stub Runner for Messaging"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">6. Spring Cloud Contract Stub Runner</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_contract_verifier_messaging.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi_stub-runner-for-messaging.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_spring_cloud_contract_stub_runner" href="#_spring_cloud_contract_stub_runner"></a>6. Spring Cloud Contract Stub Runner</h1></div></div></div><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><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
|
||||
@@ -732,4 +732,4 @@ $ curl -H <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Conte
|
||||
$ curl -X GET http://localhost:<span class="hl-number">9876</span>/api/books
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"># You will receive contents of the JSON</span></pre><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>If you want use the stubs that you have built locally, on your host,
|
||||
then you should pass the environment variable <code class="literal">-e STUBRUNNER_STUBS_MODE=LOCAL</code> and mount
|
||||
the volume of your local m2 <code class="literal">-v "${HOME}/.m2/:/root/.m2:ro"</code></p></td></tr></table></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__spring_cloud_contract_verifier_messaging.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="multi__stub_runner_for_messaging.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">5. Spring Cloud Contract Verifier Messaging </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud-contract.html">Home</a></td><td width="40%" align="right" valign="top"> 7. Stub Runner for Messaging</td></tr></table></div></body></html>
|
||||
the volume of your local m2 <code class="literal">-v "${HOME}/.m2/:/root/.m2:ro"</code></p></td></tr></table></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__spring_cloud_contract_verifier_messaging.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="multi_stub-runner-for-messaging.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">5. Spring Cloud Contract Verifier Messaging </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud-contract.html">Home</a></td><td width="40%" align="right" valign="top"> 7. Stub Runner for Messaging</td></tr></table></div></body></html>
|
||||
@@ -9,14 +9,14 @@ produced by Spring Cloud Contract Verifier.</li><li class="listitem">Messaging r
|
||||
Integration, Spring Cloud Stream, Spring AMQP, and Apache Camel. You can also set your
|
||||
own integrations.</li><li class="listitem">Acceptance tests (in JUnit or Spock) are used to verify if server-side implementation
|
||||
of the API is compliant with the contract (<span class="emphasis"><em>server tests</em></span>). A full test is generated by
|
||||
Spring Cloud Contract Verifier.</li></ul></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_why_a_contract_verifier" href="#_why_a_contract_verifier"></a>2.1 Why a Contract Verifier?</h2></div></div></div><p>Assume that we have a system consisting of multiple microservices:</p><div class="informalfigure"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/master/docs/src/main/asciidoc/images/Deps.png" alt="Microservices Architecture"></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_testing_issues" href="#_testing_issues"></a>2.1.1 Testing issues</h3></div></div></div><p>If we wanted to test the application in top left corner to determine whether it can
|
||||
Spring Cloud Contract Verifier.</li></ul></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_why_a_contract_verifier" href="#_why_a_contract_verifier"></a>2.1 Why a Contract Verifier?</h2></div></div></div><p>Assume that we have a system consisting of multiple microservices:</p><div class="informalfigure"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/2.0.x/docs/src/main/asciidoc/images/Deps.png" alt="Microservices Architecture"></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_testing_issues" href="#_testing_issues"></a>2.1.1 Testing issues</h3></div></div></div><p>If we wanted to test the application in top left corner to determine whether it can
|
||||
communicate with other services, we could do one of two things:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Deploy all microservices and perform end-to-end tests.</li><li class="listitem">Mock other microservices in unit/integration tests.</li></ul></div><p>Both have their advantages but also a lot of disadvantages.</p><p><span class="strong"><strong>Deploy all microservices and perform end to end tests</strong></span></p><p>Advantages:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Simulates production.</li><li class="listitem">Tests real communication between services.</li></ul></div><p>Disadvantages:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">To test one microservice, we have to deploy 6 microservices, a couple of databases,
|
||||
etc.</li><li class="listitem">The environment where the tests run is locked for a single suite of tests (nobody else
|
||||
would be able to run the tests in the meantime).</li><li class="listitem">They take a long time to run.</li><li class="listitem">The feedback comes very late in the process.</li><li class="listitem">They are extremely hard to debug.</li></ul></div><p><span class="strong"><strong>Mock other microservices in unit/integration tests</strong></span></p><p>Advantages:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">They provide very fast feedback.</li><li class="listitem">They have no infrastructure requirements.</li></ul></div><p>Disadvantages:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">The implementor of the service creates stubs that might have nothing to do with
|
||||
reality.</li><li class="listitem">You can go to production with passing tests and failing production.</li></ul></div><p>To solve the aforementioned issues, Spring Cloud Contract Verifier with Stub Runner was
|
||||
created. The main idea is to give you very fast feedback, without the need to set up the
|
||||
whole world of microservices. If you work on stubs, then the only applications you need
|
||||
are those that your application directly uses.</p><div class="informalfigure"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/master/docs/src/main/asciidoc/images/Stubs2.png" alt="Stubbed Services"></div></div><p>Spring Cloud Contract Verifier gives you the certainty that the stubs that you use were
|
||||
are those that your application directly uses.</p><div class="informalfigure"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/2.0.x/docs/src/main/asciidoc/images/Stubs2.png" alt="Stubbed Services"></div></div><p>Spring Cloud Contract Verifier gives you the certainty that the stubs that you use were
|
||||
created by the service that you’re calling. Also, if you can use them, it means that they
|
||||
were tested against the producer’s side. In short, you can trust those stubs.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_purposes" href="#_purposes"></a>2.2 Purposes</h2></div></div></div><p>The main purposes of Spring Cloud Contract Verifier with Stub Runner are:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">To ensure that WireMock/Messaging stubs (used when developing the client) do exactly
|
||||
what the actual server-side implementation does.</li><li class="listitem">To promote ATDD method and Microservices architectural style.</li><li class="listitem">To provide a way to publish changes in contracts that are immediately visible on both
|
||||
@@ -390,8 +390,8 @@ us. The current implementation of our system grants loans to everybody.</p><p>As
|
||||
sprint, we must develop a new feature: if a client wants to borrow too much money, then
|
||||
we mark the client as a fraud.</p><p>Technical remark - Fraud Detection has an <code class="literal">artifact-id</code> of <code class="literal">http-server</code>, while Loan
|
||||
Issuance has an artifact-id of <code class="literal">http-client</code>, and both have a <code class="literal">group-id</code> of <code class="literal">com.example</code>.</p><p>Social remark - both client and server development teams need to communicate directly and
|
||||
discuss changes while going through the process. CDC is all about communication.</p><p>The <a class="link" href="https://github.com/spring-cloud/spring-cloud-contract/tree/master/samples/standalone/dsl/http-server" target="_top">server
|
||||
side code is available here</a> and <a class="link" href="https://github.com/spring-cloud/spring-cloud-contract/tree/master/samples/standalone/dsl/http-client" target="_top">the
|
||||
discuss changes while going through the process. CDC is all about communication.</p><p>The <a class="link" href="https://github.com/spring-cloud/spring-cloud-contract/tree/2.0.x/samples/standalone/dsl/http-server" target="_top">server
|
||||
side code is available here</a> and <a class="link" href="https://github.com/spring-cloud/spring-cloud-contract/tree/2.0.x/samples/standalone/dsl/http-client" target="_top">the
|
||||
client code here</a>.</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>In this case, the producer owns the contracts. Physically, all the contract are
|
||||
in the producer’s repository.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_technical_note" href="#_technical_note"></a>2.4.1 Technical note</h3></div></div></div><p>If using the <span class="strong"><strong>SNAPSHOT</strong></span> / <span class="strong"><strong>Milestone</strong></span> / <span class="strong"><strong>Release Candidate</strong></span> versions please add the
|
||||
following section to your build:</p><p class="primary"><b>Maven. </b>
|
||||
@@ -596,7 +596,7 @@ of an identifier or a timestamp, you need not hardcode a value. You want to allo
|
||||
different ranges of values. To enable ranges of values, you can set regular expressions
|
||||
matching those values for the consumer side. You can provide the body by means of either
|
||||
a map notation or String with interpolations.
|
||||
Consult the <a class="xref" href="">???</a> section for more information. We highly recommend using the map notation!</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>You must understand the map notation in order to set up contracts. Please read the
|
||||
Consult the <a class="xref" href="multi_contract-dsl.html" title="8. Contract DSL">Chapter 8, <i>Contract DSL</i></a> section for more information. We highly recommend using the map notation!</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>You must understand the map notation in order to set up contracts. Please read the
|
||||
<a class="link" href="http://groovy-lang.org/json.html" target="_top">Groovy docs regarding JSON</a>.</p></td></tr></table></div><p>The previously shown contract is an agreement between two sides that:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p class="simpara">if an HTTP request is sent with all of</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem">a <code class="literal">PUT</code> method on the <code class="literal">/fraudcheck</code> endpoint,</li><li class="listitem">a JSON body with a <code class="literal">client.id</code> that matches the regular expression <code class="literal">[0-9]{10}</code> and
|
||||
<code class="literal">loanAmount</code> equal to <code class="literal">99999</code>,</li><li class="listitem">and a <code class="literal">Content-Type</code> header with a value of <code class="literal">application/vnd.fraud.v1+json</code>,</li></ul></div></li><li class="listitem"><p class="simpara">then an HTTP response is sent to the consumer that</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem">has status <code class="literal">200</code>,</li><li class="listitem">contains a JSON body with the <code class="literal">fraudCheckStatus</code> field containing a value <code class="literal">FRAUD</code> and
|
||||
the <code class="literal">rejectionReason</code> field having value <code class="literal">Amount too high</code>,</li><li class="listitem">and a <code class="literal">Content-Type</code> header with a value of <code class="literal">application/vnd.fraud.v1+json</code>.</li></ul></div></li></ul></div><p>Once you are ready to check the API in practice in the integration tests, you need to
|
||||
|
||||
@@ -208,7 +208,7 @@ then:
|
||||
noExceptionThrown()
|
||||
bookWasDeleted()
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">''</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'</span></pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_consumer_stub_generation" href="#_consumer_stub_generation"></a>5.4 Consumer Stub Generation</h2></div></div></div><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><p>For more information, see <a class="xref" href="">???</a> section.</p><p class="primary"><b>Maven. </b>
|
||||
a stub. Then it is parsed on the consumer side and proper stubbed routes are created.</p><p>For more information, see <a class="xref" href="multi_stub-runner-for-messaging.html" title="7. Stub Runner for Messaging">Chapter 7, <i>Stub Runner for Messaging</i></a> section.</p><p class="primary"><b>Maven. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
|
||||
@@ -545,7 +545,7 @@ goal. Example:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></plugin></span></pre><p>Under <a class="xref" href="multi__using_the_pluggable_architecture.html#scm-stub-downloader" title="10.6 Using the SCM Stub Downloader">Section 10.6, “Using the SCM Stub Downloader”</a> you can find all possible
|
||||
configuration options that you can pass either via
|
||||
the <code class="literal"><configuration><contractProperties></code> map, a system property
|
||||
or an environment variable.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="maven-sts" href="#maven-sts"></a>4.2.12 Maven Plugin and STS</h3></div></div></div><p>If you see the following exception while using STS:</p><div class="informalfigure"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/master/docs/src/main/asciidoc/images/sts_exception.png" alt="STS Exception"></div></div><p>When you click on the error marker you should see something like this:</p><pre class="programlisting"> plugin:<span class="hl-number">1.1</span>.<span class="hl-number">0.</span>M1:convert:default-convert:process-<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">test</span>-resources) org.apache.maven.plugin.PluginExecutionException: Execution default-convert of goal org.springframework.cloud:spring-
|
||||
or an environment variable.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="maven-sts" href="#maven-sts"></a>4.2.12 Maven Plugin and STS</h3></div></div></div><p>If you see the following exception while using STS:</p><div class="informalfigure"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/2.0.x/docs/src/main/asciidoc/images/sts_exception.png" alt="STS Exception"></div></div><p>When you click on the error marker you should see something like this:</p><pre class="programlisting"> plugin:<span class="hl-number">1.1</span>.<span class="hl-number">0.</span>M1:convert:default-convert:process-<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">test</span>-resources) org.apache.maven.plugin.PluginExecutionException: Execution default-convert of goal org.springframework.cloud:spring-
|
||||
cloud-contract-maven-plugin:<span class="hl-number">1.1</span>.<span class="hl-number">0.</span>M1:convert failed. at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:<span class="hl-number">145</span>) at
|
||||
org.eclipse.m2e.core.internal.embedder.MavenImpl.execute(MavenImpl.java:<span class="hl-number">331</span>) at org.eclipse.m2e.core.internal.embedder.MavenImpl$<span class="hl-number">11.</span>call(MavenImpl.java:<span class="hl-number">1362</span>) at
|
||||
...
|
||||
@@ -616,7 +616,7 @@ requires including an order number followed by an underscore. This will work reg
|
||||
2_showCart.groovy
|
||||
3_logout.groovy</pre><p>Such a tree causes Spring Cloud Contract Verifier to generate WireMock’s scenario with a
|
||||
name of <code class="literal">scenario1</code> and the three following steps:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">login marked as <code class="literal">Started</code> pointing to…​</li><li class="listitem">showCart marked as <code class="literal">Step1</code> pointing to…​</li><li class="listitem">logout marked as <code class="literal">Step2</code> which will close the scenario.</li></ol></div><p>More details about WireMock scenarios can be found at
|
||||
<a class="link" href="http://wiremock.org/stateful-behaviour.html" target="_top">http://wiremock.org/stateful-behaviour.html</a></p><p>Spring Cloud Contract Verifier also generates tests with a guaranteed order of execution.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="docker-project" href="#docker-project"></a>4.6 Docker Project</h2></div></div></div><p>We’re publishing a <code class="literal">springcloud/spring-cloud-contract</code> Docker image
|
||||
<a class="link" href="http://wiremock.org/docs/stateful-behaviour/" target="_top">http://wiremock.org/docs/stateful-behaviour/</a></p><p>Spring Cloud Contract Verifier also generates tests with a guaranteed order of execution.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="docker-project" href="#docker-project"></a>4.6 Docker Project</h2></div></div></div><p>We’re publishing a <code class="literal">springcloud/spring-cloud-contract</code> Docker image
|
||||
that contains a project that will generate tests and execute them in <code class="literal">EXPLICIT</code> mode
|
||||
against a running application.</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>The <code class="literal">EXPLICIT</code> mode means that the tests generated from contracts will send
|
||||
real requests and not the mocked ones.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_short_intro_to_maven_jars_and_binary_storage" href="#_short_intro_to_maven_jars_and_binary_storage"></a>4.6.1 Short intro to Maven, JARs and Binary storage</h3></div></div></div><p>Since the Docker image can be used by non JVM projects, it’s good to
|
||||
|
||||
1949
2.0.x/multi/multi_contract-dsl.html
Normal file
1949
2.0.x/multi/multi_contract-dsl.html
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
293
2.0.x/multi/multi_stub-runner-for-messaging.html
Normal file
293
2.0.x/multi/multi_stub-runner-for-messaging.html
Normal file
@@ -0,0 +1,293 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>7. Stub Runner for Messaging</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud-contract.html" title="Spring Cloud Contract"><link rel="up" href="multi_spring-cloud-contract.html" title="Spring Cloud Contract"><link rel="prev" href="multi__spring_cloud_contract_stub_runner.html" title="6. Spring Cloud Contract Stub Runner"><link rel="next" href="multi_contract-dsl.html" title="8. Contract DSL"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">7. Stub Runner for Messaging</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_contract_stub_runner.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi_contract-dsl.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="stub-runner-for-messaging" href="#stub-runner-for-messaging"></a>7. Stub Runner for Messaging</h1></div></div></div><p>Stub Runner can run the published stubs in memory. It can integrate with the following
|
||||
frameworks:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Spring Integration</li><li class="listitem">Spring Cloud Stream</li><li class="listitem">Spring AMQP</li></ul></div><p>It also provides entry points to integrate with any other solution on the market.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>If you 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 class="literal">stubrunner.stream.enabled=false</code> and <code class="literal">stubrunner.integration.enabled=false</code>.
|
||||
That way the only remaining framework is Spring AMQP.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_stub_triggering" href="#_stub_triggering"></a>7.1 Stub triggering</h2></div></div></div><p>To trigger a message, use the <code class="literal">StubTrigger</code> interface:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> org.springframework.cloud.contract.stubrunner;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> java.util.Collection;
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> java.util.Map;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> StubTrigger {
|
||||
|
||||
<strong class="hl-tag" style="color: blue">/**
|
||||
* Triggers an event by a given label for a given {@code groupid:artifactid} notation. You can use only {@code artifactId} too.
|
||||
*
|
||||
* Feature related to messaging.
|
||||
*
|
||||
* @return true - if managed to run a trigger
|
||||
*/</strong>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> trigger(String ivyNotation, String labelName);
|
||||
|
||||
<strong class="hl-tag" style="color: blue">/**
|
||||
* Triggers an event by a given label.
|
||||
*
|
||||
* Feature related to messaging.
|
||||
*
|
||||
* @return true - if managed to run a trigger
|
||||
*/</strong>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> trigger(String labelName);
|
||||
|
||||
<strong class="hl-tag" style="color: blue">/**
|
||||
* Triggers all possible events.
|
||||
*
|
||||
* Feature related to messaging.
|
||||
*
|
||||
* @return true - if managed to run a trigger
|
||||
*/</strong>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> trigger();
|
||||
|
||||
<strong class="hl-tag" style="color: blue">/**
|
||||
* Returns a mapping of ivy notation of a dependency to all the labels it has.
|
||||
*
|
||||
* Feature related to messaging.
|
||||
*/</strong>
|
||||
Map<String, Collection<String>> labels();
|
||||
}</pre><p>For convenience, the <code class="literal">StubFinder</code> interface extends <code class="literal">StubTrigger</code>, so you only need one
|
||||
or the other in your tests.</p><p><code class="literal">StubTrigger</code> gives you the following options to trigger a message:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><a class="xref" href="multi_stub-runner-for-messaging.html#trigger-label" title="7.1.1 Trigger by Label">Section 7.1.1, “Trigger by Label”</a></li><li class="listitem"><a class="xref" href="multi_stub-runner-for-messaging.html#trigger-group-artifact-ids" title="7.1.2 Trigger by Group and Artifact Ids">Section 7.1.2, “Trigger by Group and Artifact Ids”</a></li><li class="listitem"><a class="xref" href="multi_stub-runner-for-messaging.html#trigger-artifact-ids" title="7.1.3 Trigger by Artifact Ids">Section 7.1.3, “Trigger by Artifact Ids”</a></li><li class="listitem"><a class="xref" href="multi_stub-runner-for-messaging.html#trigger-all-messages" title="7.1.4 Trigger All Messages">Section 7.1.4, “Trigger All Messages”</a></li></ul></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="trigger-label" href="#trigger-label"></a>7.1.1 Trigger by Label</h3></div></div></div><pre class="programlisting">stubFinder.trigger(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'return_book_1'</span>)</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="trigger-group-artifact-ids" href="#trigger-group-artifact-ids"></a>7.1.2 Trigger by Group and Artifact Ids</h3></div></div></div><pre class="programlisting">stubFinder.trigger(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'org.springframework.cloud.contract.verifier.stubs:streamService'</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'return_book_1'</span>)</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="trigger-artifact-ids" href="#trigger-artifact-ids"></a>7.1.3 Trigger by Artifact Ids</h3></div></div></div><pre class="programlisting">stubFinder.trigger(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'streamService'</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'return_book_1'</span>)</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="trigger-all-messages" href="#trigger-all-messages"></a>7.1.4 Trigger All Messages</h3></div></div></div><pre class="programlisting">stubFinder.trigger()</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_stub_runner_integration" href="#_stub_runner_integration"></a>7.2 Stub Runner Integration</h2></div></div></div><p>Spring Cloud Contract Verifier Stub Runner’s messaging module gives you an easy way to
|
||||
integrate with Spring Integration. For the provided artifacts, it automatically downloads
|
||||
the stubs and registers the required routes.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_adding_the_runner_to_the_project" href="#_adding_the_runner_to_the_project"></a>7.2.1 Adding the Runner to the Project</h3></div></div></div><p>You can have both Spring Integration and Spring Cloud Contract Stub Runner on the
|
||||
classpath. Remember to annotate your test class with <code class="literal">@AutoConfigureStubRunner</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_disabling_the_functionality" href="#_disabling_the_functionality"></a>7.2.2 Disabling the functionality</h3></div></div></div><p>If you need to disable this functionality, set the
|
||||
<code class="literal">stubrunner.integration.enabled=false</code> property.</p><p>Assume that you have the following Maven repository with deployed stubs for the
|
||||
<code class="literal">integrationService</code> application:</p><pre class="programlisting">└── .m2
|
||||
└── repository
|
||||
└── io
|
||||
└── codearte
|
||||
└── accurest
|
||||
└── stubs
|
||||
└── integrationService
|
||||
├── <span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT
|
||||
│ ├── integrationService-<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT.pom
|
||||
│ ├── integrationService-<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT-stubs.jar
|
||||
│ └── maven-metadata-local.xml
|
||||
└── maven-metadata-local.xml</pre><p>Further assume the stubs contain the following structure:</p><pre class="programlisting">├── META-INF
|
||||
│ └── MANIFEST.MF
|
||||
└── repository
|
||||
├── accurest
|
||||
│ ├── bookDeleted.groovy
|
||||
│ ├── bookReturned1.groovy
|
||||
│ └── bookReturned2.groovy
|
||||
└── mappings</pre><p>Consider the following contracts (numbered <span class="strong"><strong>1</strong></span>):</p><pre class="programlisting">Contract.make {
|
||||
label <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'return_book_1'</span>
|
||||
input {
|
||||
triggeredBy(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'bookReturnedTriggered()'</span>)
|
||||
}
|
||||
outputMessage {
|
||||
sentTo(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'output'</span>)
|
||||
body(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">''</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'{ "bookName" : "foo" }'</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">''</span>)
|
||||
headers {
|
||||
header(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'BOOK-NAME'</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span>)
|
||||
}
|
||||
}
|
||||
}</pre><p>Now consider <span class="strong"><strong>2</strong></span>:</p><pre class="programlisting">Contract.make {
|
||||
label <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'return_book_2'</span>
|
||||
input {
|
||||
messageFrom(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'input'</span>)
|
||||
messageBody([
|
||||
bookName: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span>
|
||||
])
|
||||
messageHeaders {
|
||||
header(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'sample'</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'header'</span>)
|
||||
}
|
||||
}
|
||||
outputMessage {
|
||||
sentTo(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'output'</span>)
|
||||
body([
|
||||
bookName: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span>
|
||||
])
|
||||
headers {
|
||||
header(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'BOOK-NAME'</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span>)
|
||||
}
|
||||
}
|
||||
}</pre><p>and the following Spring Integration Route:</p><pre class="programlisting"><span class="hl-directive" style="color: maroon"><?xml version="1.0" encoding="UTF-8"?></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><beans:beans</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">xmlns</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"http://www.springframework.org/schema/integration"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">xmlns:xsi</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"http://www.w3.org/2001/XMLSchema-instance"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">xmlns:beans</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"http://www.springframework.org/schema/beans"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">xsi:schemaLocation</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">></span>
|
||||
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- REQUIRED FOR TESTING --></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><bridge</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">input-channel</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"output"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">output-channel</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"outputTest"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">/></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><channel</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">id</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"outputTest"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><queue/></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></channel></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></beans:beans></span></pre><p>These examples lend themselves to three scenarios:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><a class="xref" href="multi_stub-runner-for-messaging.html#integration-scenario-1" title="Scenario 1 (no input message)">the section called “Scenario 1 (no input message)”</a></li><li class="listitem"><a class="xref" href="multi_stub-runner-for-messaging.html#integration-scenario-2" title="Scenario 2 (output triggered by input)">the section called “Scenario 2 (output triggered by input)”</a></li><li class="listitem"><a class="xref" href="multi_stub-runner-for-messaging.html#integration-scenario-3" title="Scenario 3 (input with no output)">the section called “Scenario 3 (input with no output)”</a></li></ul></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="integration-scenario-1" href="#integration-scenario-1"></a>Scenario 1 (no input message)</h4></div></div></div><p>To trigger a message via the <code class="literal">return_book_1</code> label, use the <code class="literal">StubTigger</code> interface, as
|
||||
follows:</p><pre class="programlisting">stubFinder.trigger(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'return_book_1'</span>)</pre><p>To listen to the output of the message sent to <code class="literal">output</code>:</p><pre class="programlisting">Message<?> receivedMessage = messaging.receive(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'outputTest'</span>)</pre><p>The received message would pass the following assertions:</p><pre class="programlisting">receivedMessage != null
|
||||
assertJsons(receivedMessage.payload)
|
||||
receivedMessage.headers.get(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'BOOK-NAME'</span>) == <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span></pre></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="integration-scenario-2" href="#integration-scenario-2"></a>Scenario 2 (output triggered by input)</h4></div></div></div><p>Since the route is set for you, you can send a message to the <code class="literal">output</code>
|
||||
destination:</p><pre class="programlisting">messaging.send(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> BookReturned(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span>), [sample: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'header'</span>], <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'input'</span>)</pre><p>To listen to the output of the message sent to <code class="literal">output</code>:</p><pre class="programlisting">Message<?> receivedMessage = messaging.receive(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'outputTest'</span>)</pre><p>The received message passes the following assertions:</p><pre class="programlisting">receivedMessage != null
|
||||
assertJsons(receivedMessage.payload)
|
||||
receivedMessage.headers.get(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'BOOK-NAME'</span>) == <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span></pre></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="integration-scenario-3" href="#integration-scenario-3"></a>Scenario 3 (input with no output)</h4></div></div></div><p>Since the route is set for you, you can send a message to the <code class="literal">input</code> destination:</p><pre class="programlisting">messaging.send(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> BookReturned(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span>), [sample: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'header'</span>], <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'delete'</span>)</pre></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_stub_runner_stream" href="#_stub_runner_stream"></a>7.3 Stub Runner Stream</h2></div></div></div><p>Spring Cloud Contract Verifier Stub Runner’s messaging module gives you an easy way to
|
||||
integrate with Spring Stream. For the provided artifacts, it automatically downloads the
|
||||
stubs and registers the required routes.</p><div class="warning" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Warning"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="images/warning.png"></td><th align="left">Warning</th></tr><tr><td align="left" valign="top"><p>If Stub Runner’s integration with Stream the <code class="literal">messageFrom</code> or <code class="literal">sentTo</code> Strings
|
||||
are resolved first as a <code class="literal">destination</code> of a channel and no such <code class="literal">destination</code> exists, the
|
||||
destination is resolved as a channel name.</p></td></tr></table></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>If you want to use Spring Cloud Stream remember, to add a dependency on
|
||||
<code class="literal">org.springframework.cloud:spring-cloud-stream-test-support</code>.</p></td></tr></table></div><p class="primary"><b>Maven. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-stream-test-support<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><scope></span>test<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></scope></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p class="primary">
|
||||
</p><p class="secondary"><b>Gradle. </b>
|
||||
</p><pre class="programlisting">testCompile <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"org.springframework.cloud:spring-cloud-stream-test-support"</span></pre><p class="secondary">
|
||||
</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_adding_the_runner_to_the_project_2" href="#_adding_the_runner_to_the_project_2"></a>7.3.1 Adding the Runner to the Project</h3></div></div></div><p>You can have both Spring Cloud Stream and Spring Cloud Contract Stub Runner on the
|
||||
classpath. Remember to annotate your test class with <code class="literal">@AutoConfigureStubRunner</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_disabling_the_functionality_2" href="#_disabling_the_functionality_2"></a>7.3.2 Disabling the functionality</h3></div></div></div><p>If you need to disable this functionality, set the <code class="literal">stubrunner.stream.enabled=false</code>
|
||||
property.</p><p>Assume that you have the following Maven repository with a deployed stubs for the
|
||||
<code class="literal">streamService</code> application:</p><pre class="programlisting">└── .m2
|
||||
└── repository
|
||||
└── io
|
||||
└── codearte
|
||||
└── accurest
|
||||
└── stubs
|
||||
└── streamService
|
||||
├── <span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT
|
||||
│ ├── streamService-<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT.pom
|
||||
│ ├── streamService-<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT-stubs.jar
|
||||
│ └── maven-metadata-local.xml
|
||||
└── maven-metadata-local.xml</pre><p>Further assume the stubs contain the following structure:</p><pre class="programlisting">├── META-INF
|
||||
│ └── MANIFEST.MF
|
||||
└── repository
|
||||
├── accurest
|
||||
│ ├── bookDeleted.groovy
|
||||
│ ├── bookReturned1.groovy
|
||||
│ └── bookReturned2.groovy
|
||||
└── mappings</pre><p>Consider the following contracts (numbered <span class="strong"><strong>1</strong></span>):</p><pre class="programlisting">Contract.make {
|
||||
label <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'return_book_1'</span>
|
||||
input { triggeredBy(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'bookReturnedTriggered()'</span>) }
|
||||
outputMessage {
|
||||
sentTo(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'returnBook'</span>)
|
||||
body(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">''</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'{ "bookName" : "foo" }'</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">''</span>)
|
||||
headers { header(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'BOOK-NAME'</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span>) }
|
||||
}
|
||||
}</pre><p>Now consider <span class="strong"><strong>2</strong></span>:</p><pre class="programlisting">Contract.make {
|
||||
label <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'return_book_2'</span>
|
||||
input {
|
||||
messageFrom(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'bookStorage'</span>)
|
||||
messageBody([
|
||||
bookName: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span>
|
||||
])
|
||||
messageHeaders { header(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'sample'</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'header'</span>) }
|
||||
}
|
||||
outputMessage {
|
||||
sentTo(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'returnBook'</span>)
|
||||
body([
|
||||
bookName: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span>
|
||||
])
|
||||
headers { header(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'BOOK-NAME'</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span>) }
|
||||
}
|
||||
}</pre><p>Now consider the following Spring configuration:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">stubrunner.repositoryRoot</span>: classpath:m2repo/repository/
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">stubrunner.ids</span>: org.springframework.cloud.contract.verifier.stubs:streamService:<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT:stubs
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">stubrunner.stubs-mode</span>: remote
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> stream</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> bindings</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> output</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> destination</span>: returnBook
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> input</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> destination</span>: bookStorage
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">server</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> port</span>: <span class="hl-number">0</span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">debug</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">true</span></pre><p>These examples lend themselves to three scenarios:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><a class="xref" href="multi_stub-runner-for-messaging.html#stream-scenario-1" title="Scenario 1 (no input message)">the section called “Scenario 1 (no input message)”</a></li><li class="listitem"><a class="xref" href="multi_stub-runner-for-messaging.html#stream-scenario-2" title="Scenario 2 (output triggered by input)">the section called “Scenario 2 (output triggered by input)”</a></li><li class="listitem"><a class="xref" href="multi_stub-runner-for-messaging.html#stream-scenario-3" title="Scenario 3 (input with no output)">the section called “Scenario 3 (input with no output)”</a></li></ul></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="stream-scenario-1" href="#stream-scenario-1"></a>Scenario 1 (no input message)</h4></div></div></div><p>To trigger a message via the <code class="literal">return_book_1</code> label, use the <code class="literal">StubTrigger</code> interface as
|
||||
follows:</p><pre class="programlisting">stubFinder.trigger(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'return_book_1'</span>)</pre><p>To listen to the output of the message sent to a channel whose <code class="literal">destination</code> is
|
||||
<code class="literal">returnBook</code>:</p><pre class="programlisting">Message<?> receivedMessage = messaging.receive(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'returnBook'</span>)</pre><p>The received message passes the following assertions:</p><pre class="programlisting">receivedMessage != null
|
||||
assertJsons(receivedMessage.payload)
|
||||
receivedMessage.headers.get(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'BOOK-NAME'</span>) == <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span></pre></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="stream-scenario-2" href="#stream-scenario-2"></a>Scenario 2 (output triggered by input)</h4></div></div></div><p>Since the route is set for you, you can send a message to the <code class="literal">bookStorage</code>
|
||||
<code class="literal">destination</code>:</p><pre class="programlisting">messaging.send(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> BookReturned(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span>), [sample: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'header'</span>], <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'bookStorage'</span>)</pre><p>To listen to the output of the message sent to <code class="literal">returnBook</code>:</p><pre class="programlisting">Message<?> receivedMessage = messaging.receive(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'returnBook'</span>)</pre><p>The received message passes the following assertions:</p><pre class="programlisting">receivedMessage != null
|
||||
assertJsons(receivedMessage.payload)
|
||||
receivedMessage.headers.get(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'BOOK-NAME'</span>) == <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span></pre></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="stream-scenario-3" href="#stream-scenario-3"></a>Scenario 3 (input with no output)</h4></div></div></div><p>Since the route is set for you, you can send a message to the <code class="literal">output</code>
|
||||
destination:</p><pre class="programlisting">messaging.send(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> BookReturned(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span>), [sample: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'header'</span>], <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'delete'</span>)</pre></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_stub_runner_spring_amqp" href="#_stub_runner_spring_amqp"></a>7.4 Stub Runner Spring AMQP</h2></div></div></div><p>Spring Cloud Contract Verifier Stub Runner’s messaging module provides an easy way to
|
||||
integrate with Spring AMQP’s Rabbit Template. For the provided artifacts, it
|
||||
automatically downloads the stubs and registers the required routes.</p><p>The integration tries to work standalone (that is, without interaction with a running
|
||||
RabbitMQ message broker). It expects a <code class="literal">RabbitTemplate</code> on the application context and
|
||||
uses it as a spring boot test named <code class="literal">@SpyBean</code>. As a result, it can use the mockito spy
|
||||
functionality to verify and inspect messages sent by the application.</p><p>On the message consumer side, the stub runner considers all <code class="literal">@RabbitListener</code> annotated
|
||||
endpoints and all <code class="literal">SimpleMessageListenerContainer</code> objects on the application context.</p><p>As messages are usually sent to exchanges in AMQP, the message contract contains the
|
||||
exchange name as the destination. Message listeners on the other side are bound to
|
||||
queues. Bindings connect an exchange to a queue. If message contracts are triggered, the
|
||||
Spring AMQP stub runner integration looks for bindings on the application context that
|
||||
match this exchange. Then it collects the queues from the Spring exchanges and tries to
|
||||
find message listeners bound to these queues. The message is triggered for all matching
|
||||
message listeners.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_adding_the_runner_to_the_project_3" href="#_adding_the_runner_to_the_project_3"></a>7.4.1 Adding the Runner to the Project</h3></div></div></div><p>You can have both Spring AMQP and Spring Cloud Contract Stub Runner on the classpath and
|
||||
set the property <code class="literal">stubrunner.amqp.enabled=true</code>. Remember to annotate your test class
|
||||
with <code class="literal">@AutoConfigureStubRunner</code>.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>If you already have Stream and Integration on the classpath, you need
|
||||
to disable them explicitly by setting the <code class="literal">stubrunner.stream.enabled=false</code> and
|
||||
<code class="literal">stubrunner.integration.enabled=false</code> properties.</p></td></tr></table></div><p>Assume that you have the following Maven repository with a deployed stubs for the
|
||||
<code class="literal">spring-cloud-contract-amqp-test</code> application.</p><pre class="programlisting">└── .m2
|
||||
└── repository
|
||||
└── com
|
||||
└── example
|
||||
└── spring-cloud-contract-amqp-<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">test</span>
|
||||
├── <span class="hl-number">0.4</span>.<span class="hl-number">0</span>-SNAPSHOT
|
||||
│ ├── spring-cloud-contract-amqp-<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">test</span>-<span class="hl-number">0.4</span>.<span class="hl-number">0</span>-SNAPSHOT.pom
|
||||
│ ├── spring-cloud-contract-amqp-<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">test</span>-<span class="hl-number">0.4</span>.<span class="hl-number">0</span>-SNAPSHOT-stubs.jar
|
||||
│ └── maven-metadata-local.xml
|
||||
└── maven-metadata-local.xml</pre><p>Further assume that the stubs contain the following structure:</p><pre class="programlisting">├── META-INF
|
||||
│ └── MANIFEST.MF
|
||||
└── contracts
|
||||
└── shouldProduceValidPersonData.groovy</pre><p>Consider the following contract:</p><pre class="programlisting">Contract.make {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Human readable description</span>
|
||||
description <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'Should produce valid person data'</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Label by means of which the output message can be triggered</span>
|
||||
label <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'contract-test.person.created.event'</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// input to the contract</span>
|
||||
input {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// the contract will be triggered by a method</span>
|
||||
triggeredBy(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'createPerson()'</span>)
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// output message of the contract</span>
|
||||
outputMessage {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// destination to which the output message will be sent</span>
|
||||
sentTo <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'contract-test.exchange'</span>
|
||||
headers {
|
||||
header(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'contentType'</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'application/json'</span>)
|
||||
header(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'__TypeId__'</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'org.springframework.cloud.contract.stubrunner.messaging.amqp.Person'</span>)
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// the body of the output message</span>
|
||||
body ([
|
||||
id: $(consumer(<span class="hl-number">9</span>), producer(regex(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"[0-9]+"</span>))),
|
||||
name: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"me"</span>
|
||||
])
|
||||
}
|
||||
}</pre><p>Now consider the following Spring configuration:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">stubrunner</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> repositoryRoot</span>: classpath:m2repo/repository/
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> ids</span>: org.springframework.cloud.contract.verifier.stubs.amqp:spring-cloud-contract-amqp-test:<span class="hl-number">0.4</span>.<span class="hl-number">0</span>-SNAPSHOT:stubs
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> stubs-mode</span>: remote
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> amqp</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> enabled</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">true</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">server</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> port</span>: <span class="hl-number">0</span></pre><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_triggering_the_message" href="#_triggering_the_message"></a>Triggering the message</h4></div></div></div><p>To trigger a message using the contract above, use the <code class="literal">StubTrigger</code> interface as
|
||||
follows:</p><pre class="programlisting">stubTrigger.trigger(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"contract-test.person.created.event"</span>)</pre><p>The message has a destination of <code class="literal">contract-test.exchange</code>, so the Spring AMQP stub runner
|
||||
integration looks for bindings related to this exchange.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Binding binding() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> BindingBuilder.bind(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Queue(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"test.queue"</span>)).to(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> DirectExchange(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"contract-test.exchange"</span>)).with(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"#"</span>);
|
||||
}</pre><p>The binding definition binds the queue <code class="literal">test.queue</code>. As a result, the following listener
|
||||
definition is matched and invoked with the contract message.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory,
|
||||
MessageListenerAdapter listenerAdapter) {
|
||||
SimpleMessageListenerContainer container = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> SimpleMessageListenerContainer();
|
||||
container.setConnectionFactory(connectionFactory);
|
||||
container.setQueueNames(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"test.queue"</span>);
|
||||
container.setMessageListener(listenerAdapter);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> container;
|
||||
}</pre><p>Also, the following annotated listener matches and is invoked:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@RabbitListener(bindings = @QueueBinding(
|
||||
value = @Queue(value = "test.queue"),
|
||||
exchange = @Exchange(value = "contract-test.exchange", ignoreDeclarationExceptions = "true")))</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> handlePerson(Person person) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.person = person;
|
||||
}</pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The message is directly handed over to the <code class="literal">onMessage</code> method of the
|
||||
<code class="literal">MessageListener</code> associated with the matching <code class="literal">SimpleMessageListenerContainer</code>.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_spring_amqp_test_configuration" href="#_spring_amqp_test_configuration"></a>Spring AMQP Test Configuration</h4></div></div></div><p>In order to avoid Spring AMQP trying to connect to a running broker during our tests
|
||||
configure a mock <code class="literal">ConnectionFactory</code>.</p><p>To disable the mocked ConnectionFactory, set the following property:
|
||||
<code class="literal">stubrunner.amqp.mockConnection=false</code></p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">stubrunner</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> amqp</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> mockConnection</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">false</span></pre></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__spring_cloud_contract_stub_runner.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="multi_contract-dsl.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">6. Spring Cloud Contract Stub Runner </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud-contract.html">Home</a></td><td width="40%" align="right" valign="top"> 8. Contract DSL</td></tr></table></div></body></html>
|
||||
File diff suppressed because one or more lines are too long
@@ -53,7 +53,7 @@ Spring Cloud Contract Verifier.</simpara>
|
||||
<informalfigure>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/master/docs/src/main/asciidoc/images/Deps.png"/>
|
||||
<imagedata fileref="https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/2.0.x/docs/src/main/asciidoc/images/Deps.png"/>
|
||||
</imageobject>
|
||||
<textobject><phrase>Microservices Architecture</phrase></textobject>
|
||||
</mediaobject>
|
||||
@@ -128,7 +128,7 @@ are those that your application directly uses.</simpara>
|
||||
<informalfigure>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/master/docs/src/main/asciidoc/images/Stubs2.png"/>
|
||||
<imagedata fileref="https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/2.0.x/docs/src/main/asciidoc/images/Stubs2.png"/>
|
||||
</imageobject>
|
||||
<textobject><phrase>Stubbed Services</phrase></textobject>
|
||||
</mediaobject>
|
||||
@@ -707,8 +707,8 @@ we mark the client as a fraud.</simpara>
|
||||
Issuance has an artifact-id of <literal>http-client</literal>, and both have a <literal>group-id</literal> of <literal>com.example</literal>.</simpara>
|
||||
<simpara>Social remark - both client and server development teams need to communicate directly and
|
||||
discuss changes while going through the process. CDC is all about communication.</simpara>
|
||||
<simpara>The <link xl:href="https://github.com/spring-cloud/spring-cloud-contract/tree/master/samples/standalone/dsl/http-server">server
|
||||
side code is available here</link> and <link xl:href="https://github.com/spring-cloud/spring-cloud-contract/tree/master/samples/standalone/dsl/http-client">the
|
||||
<simpara>The <link xl:href="https://github.com/spring-cloud/spring-cloud-contract/tree/2.0.x/samples/standalone/dsl/http-server">server
|
||||
side code is available here</link> and <link xl:href="https://github.com/spring-cloud/spring-cloud-contract/tree/2.0.x/samples/standalone/dsl/http-client">the
|
||||
client code here</link>.</simpara>
|
||||
<tip>
|
||||
<simpara>In this case, the producer owns the contracts. Physically, all the contract are
|
||||
@@ -994,7 +994,7 @@ of an identifier or a timestamp, you need not hardcode a value. You want to allo
|
||||
different ranges of values. To enable ranges of values, you can set regular expressions
|
||||
matching those values for the consumer side. You can provide the body by means of either
|
||||
a map notation or String with interpolations.
|
||||
Consult the <xref linkend="contract_dsl"/> section for more information. We highly recommend using the map notation!</simpara>
|
||||
Consult the <xref linkend="contract-dsl"/> section for more information. We highly recommend using the map notation!</simpara>
|
||||
<tip>
|
||||
<simpara>You must understand the map notation in order to set up contracts. Please read the
|
||||
<link xl:href="http://groovy-lang.org/json.html">Groovy docs regarding JSON</link>.</simpara>
|
||||
@@ -1513,7 +1513,7 @@ consumer will you break with your local changes.</simpara>
|
||||
<title>Repo structure</title>
|
||||
<simpara>Let’s assume that we have a producer with coordinates <literal>com.example:server</literal> and 3 consumers: <literal>client1</literal>,
|
||||
<literal>client2</literal>, <literal>client3</literal>. Then in the repository with common contracts you would have the following setup
|
||||
(which you can checkout <link xl:href="https://github.com/spring-cloud/spring-cloud-contract/tree/master/samples/standalone/contracts">here</link>):</simpara>
|
||||
(which you can checkout <link xl:href="https://github.com/spring-cloud/spring-cloud-contract/tree/2.0.x/samples/standalone/contracts">here</link>):</simpara>
|
||||
<programlisting language="bash" linenumbering="unnumbered">├── com
|
||||
│ └── example
|
||||
│ └── server
|
||||
@@ -1550,14 +1550,14 @@ one to one to the contents of the repo.</simpara>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.0.3.RELEASE</version>
|
||||
<version>2.0.4.RELEASE</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<spring-cloud-contract.version>2.1.0.BUILD-SNAPSHOT</spring-cloud-contract.version>
|
||||
<spring-cloud-contract.version>2.0.2.BUILD-SNAPSHOT</spring-cloud-contract.version>
|
||||
<spring-cloud-release.version>Finchley.BUILD-SNAPSHOT</spring-cloud-release.version>
|
||||
<excludeBuildFolders>true</excludeBuildFolders>
|
||||
</properties>
|
||||
@@ -1940,7 +1940,7 @@ Artifactory or Nexus. Starting from Spring Cloud Contract version 2.0.0 we provi
|
||||
mechanisms to store contracts and stubs in a SCM repository. Currently the
|
||||
only supported SCM is Git.</simpara>
|
||||
<simpara>The repository would have to the following setup
|
||||
(which you can checkout <link xl:href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/2.0.x/contracts_git/">here</link>):</simpara>
|
||||
(which you can checkout <link xl:href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/master/contracts_git/">here</link>):</simpara>
|
||||
<screen>.
|
||||
└── META-INF
|
||||
└── com.example
|
||||
@@ -2153,7 +2153,7 @@ is not met.</simpara>
|
||||
<title>Pact Consumer</title>
|
||||
<simpara>The consumer uses Pact framework to generate Pact files. The
|
||||
Pact files are sent to the Pact Broker. An example of such
|
||||
setup can be found <link xl:href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/2.0.x/consumer_pact">here</link>.</simpara>
|
||||
setup can be found <link xl:href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/master/consumer_pact">here</link>.</simpara>
|
||||
</section>
|
||||
<section xml:id="_producer_3">
|
||||
<title>Producer</title>
|
||||
@@ -2161,7 +2161,7 @@ setup can be found <link xl:href="https://github.com/spring-cloud-samples/spring
|
||||
same mechanism we use for external contracts. We route Spring Cloud Contract
|
||||
to use the Pact implementation via the URL that contains
|
||||
the <literal>pact://</literal> protocol. It’s enough to pass the URL to the
|
||||
Pact Broker. An example of such setup can be found <link xl:href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/2.0.x/producer_pact">here</link>.</simpara>
|
||||
Pact Broker. An example of such setup can be found <link xl:href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/master/producer_pact">here</link>.</simpara>
|
||||
<formalpara>
|
||||
<title>Maven</title>
|
||||
<para>
|
||||
@@ -2248,7 +2248,7 @@ contracts {
|
||||
(for every single consumer define the expectations) but you’d prefer
|
||||
to do Producer Contracts (the producer provides the contracts and
|
||||
publishes stubs), it’s enough to use Spring Cloud Contract with
|
||||
Stub Runner option. An example of such setup can be found <link xl:href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/2.0.x/consumer_pact_stubrunner">here</link>.</simpara>
|
||||
Stub Runner option. An example of such setup can be found <link xl:href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/master/consumer_pact_stubrunner">here</link>.</simpara>
|
||||
<simpara>First, remember to add Stub Runner and Spring Cloud Contract Pact module
|
||||
as test dependencies.</simpara>
|
||||
<formalpara>
|
||||
@@ -3304,7 +3304,7 @@ or an environment variable.</simpara>
|
||||
<informalfigure>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/master/docs/src/main/asciidoc/images/sts_exception.png"/>
|
||||
<imagedata fileref="https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/2.0.x/docs/src/main/asciidoc/images/sts_exception.png"/>
|
||||
</imageobject>
|
||||
<textobject><phrase>STS Exception</phrase></textobject>
|
||||
</mediaobject>
|
||||
@@ -3440,7 +3440,7 @@ name of <literal>scenario1</literal> and the three following steps:</simpara>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<simpara>More details about WireMock scenarios can be found at
|
||||
<link xl:href="http://wiremock.org/stateful-behaviour.html">http://wiremock.org/stateful-behaviour.html</link></simpara>
|
||||
<link xl:href="http://wiremock.org/docs/stateful-behaviour/">http://wiremock.org/docs/stateful-behaviour/</link></simpara>
|
||||
<simpara>Spring Cloud Contract Verifier also generates tests with a guaranteed order of execution.</simpara>
|
||||
</section>
|
||||
<section xml:id="docker-project">
|
||||
@@ -5320,7 +5320,7 @@ the volume of your local m2 <literal>-v "${HOME}/.m2/:/root/.m2:ro"</literal></s
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
<chapter xml:id="_stub_runner_for_messaging">
|
||||
<chapter xml:id="stub-runner-for-messaging">
|
||||
<title>Stub Runner for Messaging</title>
|
||||
<simpara>Stub Runner can run the published stubs in memory. It can integrate with the following
|
||||
frameworks:</simpara>
|
||||
@@ -5537,7 +5537,7 @@ follows:</simpara>
|
||||
assertJsons(receivedMessage.payload)
|
||||
receivedMessage.headers.get('BOOK-NAME') == 'foo'</programlisting>
|
||||
</section>
|
||||
<section xml:id="integration-scenario-1">
|
||||
<section xml:id="integration-scenario-2">
|
||||
<title>Scenario 2 (output triggered by input)</title>
|
||||
<simpara>Since the route is set for you, you can send a message to the <literal>output</literal>
|
||||
destination:</simpara>
|
||||
@@ -5836,7 +5836,7 @@ configure a mock <literal>ConnectionFactory</literal>.</simpara>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
<chapter xml:id="_contract_dsl">
|
||||
<chapter xml:id="contract-dsl">
|
||||
<title>Contract DSL</title>
|
||||
<simpara>Spring Cloud Contract supports out of the box 2 types of DSL. One written in
|
||||
<literal>Groovy</literal> and one written in <literal>YAML</literal>.</simpara>
|
||||
|
||||
Reference in New Issue
Block a user