diff --git a/2.1.x/multi/multi__customization.html b/2.1.x/multi/multi__customization.html index 885bc14127..3bcaae3da0 100644 --- a/2.1.x/multi/multi__customization.html +++ b/2.1.x/multi/multi__customization.html @@ -7,7 +7,7 @@ maintain the static compatibility. Later in this document, you can see examples import java.util.regex.Pattern; -/** +/** * If you want to use {@link Pattern} directly in your tests * then you can create a class resembling this one. It can * contain all the {@link Pattern} you want to use in the DSL. @@ -25,7 +25,7 @@ maintain the static compatibility. Later in this document, you can see examples * and {@code c()} for the consumer side. * * @author Marcin Grzejszczak - */ + */ //tag::impl[] public class PatternUtils { @@ -41,9 +41,9 @@ maintain the static compatibility. Later in this document, you can see examples //remove::end[return] } - /** + /** * Makes little sense but it's just an example ;) - */ + */ public static Pattern ok() { //remove::start[] return Pattern.compile("OK"); @@ -54,7 +54,7 @@ maintain the static compatibility. Later in this document, you can see examples import org.springframework.cloud.contract.spec.internal.ClientDslProperty; -/** +/** * DSL Properties passed to the DSL from the consumer's perspective. * That means that on the input side {@code Request} for HTTP * or {@code Input} for messaging you can have a regular expression. @@ -62,10 +62,10 @@ maintain the static compatibility. Later in this document, you can see examples * you have to have a concrete value. * * @author Marcin Grzejszczak - */ + */ //tag::impl[] public class ConsumerUtils { - /** + /** * Consumer side property. By using the {@link ClientDslProperty} * you can omit most of boilerplate code from the perspective * of dynamic values. Example @@ -83,13 +83,13 @@ maintain the static compatibility. Later in this document, you can see examples * and which one to the producer. * * @author Marcin Grzejszczak - */ + */ public static ClientDslProperty oldEnough() { //remove::start[] // this example is not the best one and // theoretically you could just pass the regex instead of `ServerDslProperty` but // it's just to show some new tricks :) - return new ClientDslProperty(PatternUtils.oldEnough(), 40); + return new ClientDslProperty(PatternUtils.oldEnough(), 40); //remove::end[return] } @@ -98,7 +98,7 @@ maintain the static compatibility. Later in this document, you can see examples import org.springframework.cloud.contract.spec.internal.ServerDslProperty; -/** +/** * DSL Properties passed to the DSL from the producer's perspective. * That means that on the input side {@code Request} for HTTP * or {@code Input} for messaging you have to have a concrete value. @@ -106,11 +106,11 @@ maintain the static compatibility. Later in this document, you can see examples * you can have a regular expression. * * @author Marcin Grzejszczak - */ + */ //tag::impl[] public class ProducerUtils { - /** + /** * Producer side property. By using the {@link ProducerUtils} * you can omit most of boilerplate code from the perspective * of dynamic values. Example @@ -126,7 +126,7 @@ maintain the static compatibility. Later in this document, you can see examples * * That way it's in the implementation that we decide what value we will pass to the consumer * and which one to the producer. - */ + */ public static ServerDslProperty ok() { // this example is not the best one and // theoretically you could just pass the regex instead of `ServerDslProperty` but @@ -204,7 +204,7 @@ then: } } response { - status 200 + status 200 body(""" { "status": "${value(ProducerUtils.ok())}" diff --git a/2.1.x/multi/multi__migrations.html b/2.1.x/multi/multi__migrations.html index 2f6342b768..cb308e5a09 100644 --- a/2.1.x/multi/multi__migrations.html +++ b/2.1.x/multi/multi__migrations.html @@ -5,9 +5,9 @@ the project’s

12.1 1.0.x → 1.1.x

This section covers upgrading from version 1.0 to version 1.1.

12.1.1 New structure of generated stubs

In 1.1.x we have introduced a change to the structure of generated stubs. If you have been using the @AutoConfigureWireMock notation to use the stubs from the classpath, it no longer works. The following example shows how the @AutoConfigureWireMock notation -used to work:

@AutoConfigureWireMock(stubs = "classpath:/customer-stubs/mappings", port = 8084)

You must either change the location of the stubs to: +used to work:

@AutoConfigureWireMock(stubs = "classpath:/customer-stubs/mappings", port = 8084)

You must either change the location of the stubs to: classpath:…​/META-INF/groupId/artifactId/version/mappings or use the new -classpath-based @AutoConfigureStubRunner, as shown in the following example:

@AutoConfigureWireMock(stubs = "classpath:customer-stubs/META-INF/travel.components/customer-contract/1.0.2-SNAPSHOT/mappings/", port = 8084)

If you do not want to use @AutoConfigureStubRunner and you want to remain with the old +classpath-based @AutoConfigureStubRunner, as shown in the following example:

@AutoConfigureWireMock(stubs = "classpath:customer-stubs/META-INF/travel.components/customer-contract/1.0.2-SNAPSHOT/mappings/", port = 8084)

If you do not want to use @AutoConfigureStubRunner and you want to remain with the old structure, set your plugin tasks accordingly. The following example would work for the structure presented in the previous snippet.

Maven. 

<!-- start of pom.xml -->
@@ -90,7 +90,7 @@ detail.

TemplateProcessor interface:

  • path()
  • path(int index)

See issue 388 for more detail.

12.2.4 RestAssured 3.0

Rest Assured, used in the generated test classes, got bumped to 3.0. If you manually set versions of Spring Cloud Contract and the release train -you might see the following exception:

Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile (default-testCompile) on project some-project: Compilation failure: Compilation failure:
-[ERROR] /some/path/SomeClass.java:[4,39] package com.jayway.restassured.response does not exist

This exception will occur due to the fact that the tests got generated with +you might see the following exception:

Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile (default-testCompile) on project some-project: Compilation failure: Compilation failure:
+[ERROR] /some/path/SomeClass.java:[4,39] package com.jayway.restassured.response does not exist

This exception will occur due to the fact that the tests got generated with an old version of plugin and at test execution time you have an incompatible version of the release train (and vice versa).

Done via issue 267

12.3 1.2.x → 2.0.x

\ No newline at end of file diff --git a/2.1.x/multi/multi__spring_cloud_contract_faq.html b/2.1.x/multi/multi__spring_cloud_contract_faq.html index 9a9f044dbf..a5f3588748 100644 --- a/2.1.x/multi/multi__spring_cloud_contract_faq.html +++ b/2.1.x/multi/multi__spring_cloud_contract_faq.html @@ -73,7 +73,7 @@ different approaches.

3.4.2 JAR versioning

If by versioning you mean the version of the JAR that contains the stubs then there are essentially two main approaches.

Let’s assume that you’re doing Continuous Delivery / Deployment which means that you’re generating a new version of the jar each time you go through the pipeline and that jar can go to production at any time. For example your jar version -looks like this (it got built on the 20.10.2016 at 20:15:21) :

1.0.0.20161020-201521-RELEASE

In that case your generated stub jar will look like this.

1.0.0.20161020-201521-RELEASE-stubs.jar

In this case you should inside your application.yml or @AutoConfigureStubRunner when referencing stubs provide the +looks like this (it got built on the 20.10.2016 at 20:15:21) :

1.0.0.20161020-201521-RELEASE

In that case your generated stub jar will look like this.

1.0.0.20161020-201521-RELEASE-stubs.jar

In this case you should inside your application.yml or @AutoConfigureStubRunner when referencing stubs provide the latest version of the stubs. You can do that by passing the + sign. Example

@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:8080"})

If the versioning however is fixed (e.g. 1.0.4.RELEASE or 2.1.1) then you have to set the concrete value of the jar version. Example for 2.1.1.

@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:2.1.1:stubs:8080"})

3.4.3 Dev or prod stubs

You can manipulate the classifier to run the tests against current development version of the stubs of other services or the ones that were deployed to production. If you alter your build to deploy the stubs with the prod-stubs classifier @@ -100,7 +100,7 @@ consumer you will break with your local changes.

As you can see under the slash-delimited groupid / artifact id folder (com/example/server) you have expectations of the 3 consumers (client1, client2 and client3). Expectations are the standard Groovy DSL contract files as described throughout this documentation. This repository has to produce a JAR file that maps -one to one to the contents of the repo.

Example of a pom.xml inside the server folder.

<?xml version="1.0" encoding="UTF-8"?>
+one to one to the contents of the repo.

Example of a pom.xml inside the server folder.

<?xml version="1.0" encoding="UTF-8"?>
 <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 		 xmlns="http://maven.apache.org/POM/4.0.0"
 		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
@@ -211,7 +211,7 @@ one to one to the contents of the repo.

Example of a </project>

As you can see there are no dependencies other than the Spring Cloud Contract Maven Plugin. Those poms are necessary for the consumer side to run mvn clean install -DskipTests to locally install - stubs of the producer project.

The pom.xml in the root folder can look like this:

<?xml version="1.0" encoding="UTF-8"?>
+ stubs of the producer project.

The pom.xml in the root folder can look like this:

<?xml version="1.0" encoding="UTF-8"?>
 <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 		 xmlns="http://maven.apache.org/POM/4.0.0"
 		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
@@ -682,14 +682,14 @@ dependencies {
     testCompile("org.springframework.cloud:spring-cloud-contract-pact")
 }

Next, just pass the URL of the Pact Broker to repositoryRoot, prefixed -with pact:// protocol. E.g. pact://http://localhost:8085

@RunWith(SpringRunner.class)
-@SpringBootTest
-@AutoConfigureStubRunner(stubsMode = StubRunnerProperties.StubsMode.REMOTE,
+with pact:// protocol. E.g. pact://http://localhost:8085

@RunWith(SpringRunner.class)
+@SpringBootTest
+@AutoConfigureStubRunner(stubsMode = StubRunnerProperties.StubsMode.REMOTE,
 		ids = "com.example:beer-api-producer-pact",
-		repositoryRoot = "pact://http://localhost:8085")
+		repositoryRoot = "pact://http://localhost:8085")
 public class BeerControllerTest {
     //Inject the port of the running stub
-    @StubRunnerPort("beer-api-producer-pact") int producerPort;
+    @StubRunnerPort("beer-api-producer-pact") int producerPort;
     //...
 }

With such a setup:

  • Pact files will be downloaded from the Pact Broker
  • Spring Cloud Contract will convert the Pact files into stub definitions
  • The stub servers will be started and fed with stubs

For more information about Pact support you can go to the Section 10.7, “Using the Pact Stub Downloader” section.

3.8 How can I debug the request/response being sent by the generated tests client?

The generated tests all boil down to RestAssured in some form or fashion which relies on Apache HttpClient. HttpClient has a facility called wire logging which logs the entire request and response to HttpClient. Spring Boot has a logging common application property for doing this sort of thing, just add this to your application properties

logging.level.org.apache.http.wire=DEBUG

3.8.1 How can I debug the mapping/request/response being sent by WireMock?

Starting from version 1.2.0 we turn on WireMock logging to diff --git a/2.1.x/multi/multi__spring_cloud_contract_stub_runner.html b/2.1.x/multi/multi__spring_cloud_contract_stub_runner.html index b3e4488378..181cb341b2 100644 --- a/2.1.x/multi/multi__spring_cloud_contract_stub_runner.html +++ b/2.1.x/multi/multi__spring_cloud_contract_stub_runner.html @@ -212,7 +212,7 @@ producer stubs.

The producer would setup the contr structure in your stubs jar.

└── META-INF
     └── com.example
         └── beer-api-producer-restdocs
-            └── 2.0.0
+            └── 2.0.0
                 ├── contracts
                 │   └── nested
                 │       └── contract2.groovy
@@ -229,12 +229,12 @@ the configuration files for the given HTTP server stub.

Spring Cloud Contr can extend, for WireMock - org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockHttpServerStubConfigurer. In the configure method you can provide your own, custom configuration for the given stub. The use case might be starting WireMock for the given artifact id, on an HTTPs port. Example:

WireMockHttpServerStubConfigurer implementation.  -

@CompileStatic
+

@CompileStatic
 static class HttpsForFraudDetection extends WireMockHttpServerStubConfigurer {
 
 	private static final Log log = LogFactory.getLog(HttpsForFraudDetection)
 
-	@Override
+	@Override
 	WireMockConfiguration configure(WireMockConfiguration httpStubConfiguration, HttpServerStubConfiguration httpServerStubConfiguration) {
 		if (httpServerStubConfiguration.stubConfiguration.artifactId == "fraudDetectionServer") {
 			int httpsPort = SocketUtils.findAvailableTcpPort()
@@ -253,10 +253,10 @@ case might be starting WireMock for the given artifact id, on an HTTPs port. Exa
                                   (default: stubs)
 --maxPort, --maxp <Integer>     Maximum port value to be assigned to
                                   the WireMock instance. Defaults to
-                                  15000 (default: 15000)
+                                  15000 (default: 15000)
 --minPort, --minp <Integer>     Minimum port value to be assigned to
                                   the WireMock instance. Defaults to
-                                  10000 (default: 10000)
+                                  10000 (default: 10000)
 -p, --password                  Password to user when connecting to
                                   repository
 --phost, --proxyHost            Proxy host to use for repository
@@ -280,7 +280,7 @@ case might be starting WireMock for the given artifact id, on an HTTPs port. Exa
         "url": "/ping"
     },
     "response": {
-        "status": 200,
+        "status": 200,
         "body": "pong",
         "headers": {
             "Content-Type": "text/plain"
@@ -288,13 +288,13 @@ case might be starting WireMock for the given artifact id, on an HTTPs port. Exa
     }
 }

Viewing registered mappings

Every stubbed collaborator exposes list of defined mappings under __/admin/ endpoint.

You can also use the mappingsOutputFolder property to dump the mappings to files. For annotation based approach it would look like this

@AutoConfigureStubRunner(ids="a.b.c:loanIssuance,a.b.c:fraudDetectionServer",
-mappingsOutputFolder = "target/outputmappings/")

and for the JUnit approach like this:

@ClassRule @Shared StubRunnerRule rule = new StubRunnerRule()
+mappingsOutputFolder = "target/outputmappings/")

and for the JUnit approach like this:

@ClassRule @Shared StubRunnerRule rule = new StubRunnerRule()
 			.repoRoot("http://some_url")
 			.downloadStub("a.b.c", "loanIssuance")
 			.downloadStub("a.b.c:fraudDetectionServer")
 			.withMappingsOutputFolder("target/outputmappings")

Then if you check out the folder target/outputmappings you would see the following structure

.
-├── fraudDetectionServer_13705
-└── loanIssuance_12255

That means that there were two stubs registered. fraudDetectionServer was registered at port 13705 +├── fraudDetectionServer_13705 +└── loanIssuance_12255

That means that there were two stubs registered. fraudDetectionServer was registered at port 13705 and loanIssuance at port 12255. If we take a look at one of the files we would see (for WireMock) mappings available for the given server:

[{
   "id" : "f9152eb9-bf77-4c38-8289-90be7d10d0d7",
@@ -303,13 +303,13 @@ mappings available for the given server:

["method" : "GET"
   },
   "response" : {
-    "status" : 200,
+    "status" : 200,
     "body" : "fraudDetectionServer"
   },
   "uuid" : "f9152eb9-bf77-4c38-8289-90be7d10d0d7"
 },
 ...
-]

Messaging Stubs

Depending on the provided Stub Runner dependency and the DSL the messaging routes are automatically set up.

6.4 Stub Runner JUnit Rule and Stub Runner JUnit5 Extension

Stub Runner comes with a JUnit rule thanks to which you can very easily download and run stubs for given group and artifact id:

@ClassRule
+]

Messaging Stubs

Depending on the provided Stub Runner dependency and the DSL the messaging routes are automatically set up.

6.4 Stub Runner JUnit Rule and Stub Runner JUnit5 Extension

Stub Runner comes with a JUnit rule thanks to which you can very easily download and run stubs for given group and artifact id:

@ClassRule
 public static StubRunnerRule rule = new StubRunnerRule().repoRoot(repoRoot())
 		.stubsMode(StubRunnerProperties.StubsMode.REMOTE)
 		.downloadStub("org.springframework.cloud.contract.verifier.stubs",
@@ -317,8 +317,8 @@ mappings available for the given server:

["org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer");
 
-@BeforeClass
-@AfterClass
+@BeforeClass
+@AfterClass
 public static void setupProps() {
 	System.clearProperty("stubrunner.repository.root");
 	System.clearProperty("stubrunner.classifier");
@@ -332,14 +332,14 @@ Check their import org.springframework.cloud.contract.spec.Contract;
 
-/**
+/**
  * Contract for finding registered stubs.
  *
  * @author Marcin Grzejszczak
- */
+ */
 public interface StubFinder extends StubTrigger {
 
-	/**
+	/**
 	 * For the given groupId and artifactId tries to find the matching URL of the running
 	 * stub.
 	 * @param groupId - might be null. In that case a search only via artifactId takes
@@ -347,31 +347,31 @@ Check their 
+	 */
 	URL findStubUrl(String groupId, String artifactId) throws StubNotFoundException;
 
-	/**
+	/**
 	 * For the given Ivy notation {@code [groupId]:artifactId:[version]:[classifier]}
 	 * tries to find the matching URL of the running stub. You can also pass only
 	 * {@code artifactId}.
 	 * @param ivyNotation - Ivy representation of the Maven artifact
 	 * @return URL of a running stub or throws exception if not found
 	 * @throws StubNotFoundException in case of not finding a stub
-	 */
+	 */
 	URL findStubUrl(String ivyNotation) throws StubNotFoundException;
 
-	/**
+	/**
 	 * @return all running stubs
-	 */
+	 */
 	RunningStubs findAllRunningStubs();
 
-	/**
+	/**
 	 * @return the list of Contracts
-	 */
+	 */
 	Map<StubConfiguration, Collection<Contract>> getContracts();
 
-}

Example of usage in Spock tests:

@ClassRule
-@Shared
+}

Example of usage in Spock tests:

@ClassRule
+@Shared
 StubRunnerRule rule = new StubRunnerRule()
 		.stubsMode(StubRunnerProperties.StubsMode.REMOTE)
 		.repoRoot(StubRunnerRuleSpec.getResource("/m2repo/repository").toURI().toString())
@@ -400,7 +400,7 @@ def 'should outp
 		def url = rule.findStubUrl('fraudDetectionServer')
 	then:
 		new File("target/outputmappingsforrule", "fraudDetectionServer_${url.port}").exists()
-}

Example of usage in JUnit tests:

	@Test
+}

Example of usage in JUnit tests:

	@Test
 	public void should_start_wiremock_servers() throws Exception {
 		// expect: 'WireMocks are running'
 		then(rule.findStubUrl("org.springframework.cloud.contract.verifier.stubs",
@@ -433,7 +433,7 @@ def 'should outp
 	}
 
 }

JUnit 5 Extension example:

// Visible for Junit
-@RegisterExtension
+@RegisterExtension
 static StubRunnerExtension stubRunnerExtension = new StubRunnerExtension()
 		.repoRoot(repoRoot()).stubsMode(StubRunnerProperties.StubsMode.REMOTE)
 		.downloadStub("org.springframework.cloud.contract.verifier.stubs",
@@ -442,8 +442,8 @@ def 'should outp
 				"org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")
 		.withMappingsOutputFolder("target/outputmappingsforrule");
 
-@BeforeAll
-@AfterAll
+@BeforeAll
+@AfterAll
 static void setupProps() {
 	System.clearProperty("stubrunner.repository.root");
 	System.clearProperty("stubrunner.classifier");
@@ -461,16 +461,16 @@ def 'should outp
 MessageVerifier interface to the rule builder (e.g. rule.messageVerifier(new MyMessageVerifier())).
 If you don’t do this, then whenever you try to send a message an exception will be thrown.

6.4.1 Maven settings

The stub downloader honors Maven settings for a different local repository folder. Authentication details for repositories and profiles are currently not taken into account, so you need to specify it using the properties mentioned above.

6.4.2 Providing fixed ports

You can also run your stubs on fixed ports. You can do it in two different ways. One is to pass it in the properties, and the other via fluent API of -JUnit rule.

6.4.3 Fluent API

When using the StubRunnerRule or StubRunnerExtension you can add a stub to download and then pass the port for the last downloaded stub.

@ClassRule
+JUnit rule.

6.4.3 Fluent API

When using the StubRunnerRule or StubRunnerExtension you can add a stub to download and then pass the port for the last downloaded stub.

@ClassRule
 public static StubRunnerRule rule = new StubRunnerRule().repoRoot(repoRoot())
 		.stubsMode(StubRunnerProperties.StubsMode.REMOTE)
 		.downloadStub("org.springframework.cloud.contract.verifier.stubs",
 				"loanIssuance")
-		.withPort(12345).downloadStub(
+		.withPort(12345).downloadStub(
 				"org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer:12346");
 
-@BeforeClass
-@AfterClass
+@BeforeClass
+@AfterClass
 public static void setupProps() {
 	System.clearProperty("stubrunner.repository.root");
 	System.clearProperty("stubrunner.classifier");
@@ -479,28 +479,28 @@ JUnit rule.

"fraudDetectionServer")) .isEqualTo(URI.create("http://localhost:12346").toURL());

6.4.4 Stub Runner with Spring

Sets up Spring configuration of the Stub Runner project.

By providing a list of stubs inside your configuration file the Stub Runner automatically downloads and registers in WireMock the selected stubs.

If you want to find the URL of your stubbed dependency you can autowire the StubFinder interface and use -its methods as presented below:

@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
-@SpringBootTest(properties = [" stubrunner.cloud.enabled=false",
+its methods as presented below:

@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
+@SpringBootTest(properties = [" stubrunner.cloud.enabled=false",
 		'foo=${stubrunner.runningstubs.fraudDetectionServer.port}',
-		'fooWithGroup=${stubrunner.runningstubs.org.springframework.cloud.contract.verifier.stubs.fraudDetectionServer.port}'])
-@AutoConfigureStubRunner(mappingsOutputFolder = "target/outputmappings/",
-		httpServerStubConfigurer = HttpsForFraudDetection)
-@ActiveProfiles("test")
+		'fooWithGroup=${stubrunner.runningstubs.org.springframework.cloud.contract.verifier.stubs.fraudDetectionServer.port}'])
+@AutoConfigureStubRunner(mappingsOutputFolder = "target/outputmappings/",
+		httpServerStubConfigurer = HttpsForFraudDetection)
+@ActiveProfiles("test")
 class StubRunnerConfigurationSpec extends Specification {
 
-	@Autowired
+	@Autowired
 	StubFinder stubFinder
-	@Autowired
+	@Autowired
 	Environment environment
-	@StubRunnerPort("fraudDetectionServer")
+	@StubRunnerPort("fraudDetectionServer")
 	int fraudDetectionServerPort
-	@StubRunnerPort("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")
+	@StubRunnerPort("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")
 	int fraudDetectionServerPortWithGroupId
-	@Value('${foo}')
+	@Value('${foo}')
 	Integer foo
 
-	@BeforeClass
-	@AfterClass
+	@BeforeClass
+	@AfterClass
 	void setupProps() {
 		System.clearProperty("stubrunner.repository.root")
 		System.clearProperty("stubrunner.classifier")
@@ -552,18 +552,18 @@ its methods as presented below:

int fraudPort = stubFinder.findAllRunningStubs().getPort("fraudDetectionServer")
 		expect:
-			fraudPort > 0
+			fraudPort > 0
 			environment.getProperty("foo", Integer) == fraudPort
 			environment.getProperty("fooWithGroup", Integer) == fraudPort
 			foo == fraudPort
 	}
 
-	@Issue("#573")
+	@Issue("#573")
 	def 'should be able to retrieve the port of a running stub via an annotation'() {
 		given:
 			int fraudPort = stubFinder.findAllRunningStubs().getPort("fraudDetectionServer")
 		expect:
-			fraudPort > 0
+			fraudPort > 0
 			fraudDetectionServerPort == fraudPort
 			fraudDetectionServerPortWithGroupId == fraudPort
 	}
@@ -575,16 +575,16 @@ its methods as presented below:

new File("target/outputmappings/", "fraudDetectionServer_${url.port}").exists()
 	}
 
-	@Configuration
-	@EnableAutoConfiguration
+	@Configuration
+	@EnableAutoConfiguration
 	static class Config {}
 
-	@CompileStatic
+	@CompileStatic
 	static class HttpsForFraudDetection extends WireMockHttpServerStubConfigurer {
 
 		private static final Log log = LogFactory.getLog(HttpsForFraudDetection)
 
-		@Override
+		@Override
 		WireMockConfiguration configure(WireMockConfiguration httpStubConfiguration, HttpServerStubConfiguration httpServerStubConfiguration) {
 			if (httpServerStubConfiguration.stubConfiguration.artifactId == "fraudDetectionServer") {
 				int httpsPort = SocketUtils.findAvailableTcpPort()
@@ -611,9 +611,9 @@ Below you can find an example of achieving the same result by setting values on
 for every registered WireMock server. Example for Stub Runner ids
  com.example:foo, com.example:bar.

  • stubrunner.runningstubs.foo.port
  • stubrunner.runningstubs.com.example.foo.port
  • stubrunner.runningstubs.bar.port
  • stubrunner.runningstubs.com.example.bar.port

Which you can reference in your code.

You can also use the @StubRunnerPort annotation to inject the port of a running stub. Value of the annotation can be the groupid:artifactid or just the artifactid. Example for Stub Runner ids -com.example:foo, com.example:bar.

@StubRunnerPort("foo")
+com.example:foo, com.example:bar.

@StubRunnerPort("foo")
 int fooPort;
-@StubRunnerPort("com.example:bar")
+@StubRunnerPort("com.example:bar")
 int barPort;

6.5 Stub Runner Spring Cloud

Stub Runner can integrate with Spring Cloud.

For real life examples you can check the

6.5.1 Stubbing Service Discovery

The most important feature of Stub Runner Spring Cloud is the fact that it’s stubbing

  • DiscoveryClient
  • Ribbon ServerList

that means that regardless of the fact whether you’re using Zookeeper, Consul, Eureka or anything else, you don’t need that in your tests. We’re starting WireMock instances of your dependencies and we’re telling your application whenever you’re using Feign, load balanced RestTemplate or DiscoveryClient directly, to call those stubbed servers instead of calling the real Service Discovery tool.

For example this test will pass

def 'should make service discovery work'() {
@@ -652,12 +652,12 @@ or a subdirectory called config or in spring cloud stubrunner from your terminal window to start
-the Stub Runner server. It will be available at port 8750.

6.6.2 Endpoints

HTTP

  • GET /stubs - returns a list of all running stubs in ivy:integer notation
  • GET /stubs/{ivy} - returns a port for the given ivy notation (when calling the endpoint ivy can also be artifactId only)

Messaging

For Messaging

  • GET /triggers - returns a list of all running labels in ivy : [ label1, label2 …​] notation
  • POST /triggers/{label} - executes a trigger with label
  • POST /triggers/{ivy}/{label} - executes a trigger with label for the given ivy notation (when calling the endpoint ivy can also be artifactId only)

6.6.3 Example

@ContextConfiguration(classes = StubRunnerBoot, loader = SpringBootContextLoader)
-@SpringBootTest(properties = "spring.cloud.zookeeper.enabled=false")
-@ActiveProfiles("test")
+the Stub Runner server. It will be available at port 8750.

6.6.2 Endpoints

HTTP

  • GET /stubs - returns a list of all running stubs in ivy:integer notation
  • GET /stubs/{ivy} - returns a port for the given ivy notation (when calling the endpoint ivy can also be artifactId only)

Messaging

For Messaging

  • GET /triggers - returns a list of all running labels in ivy : [ label1, label2 …​] notation
  • POST /triggers/{label} - executes a trigger with label
  • POST /triggers/{ivy}/{label} - executes a trigger with label for the given ivy notation (when calling the endpoint ivy can also be artifactId only)

6.6.3 Example

@ContextConfiguration(classes = StubRunnerBoot, loader = SpringBootContextLoader)
+@SpringBootTest(properties = "spring.cloud.zookeeper.enabled=false")
+@ActiveProfiles("test")
 class StubRunnerBootSpec extends Specification {
 
-	@Autowired
+	@Autowired
 	StubRunning stubRunning
 
 	def setup() {
@@ -677,8 +677,8 @@ the Stub Runner server. It will be available at port 8750<
 		when:
 			def response = RestAssuredMockMvc.get("/stubs/${stubId}")
 		then:
-			response.statusCode == 200
-			Integer.valueOf(response.body.asString()) > 0
+			response.statusCode == 200
+			Integer.valueOf(response.body.asString()) > 0
 		where:
 			stubId << ['org.springframework.cloud.contract.verifier.stubs:bootService:+:stubs',
 					   'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs',
@@ -691,7 +691,7 @@ the Stub Runner server. It will be available at port 8750<
 		when:
 			def response = RestAssuredMockMvc.get("/stubs/a:b:c:d")
 		then:
-			response.statusCode == 404
+			response.statusCode == 404
 	}
 
 	def 'should return a list of messaging labels that can be triggered when version and classifier are passed'() {
@@ -709,9 +709,9 @@ the Stub Runner server. It will be available at port 8750<
 		when:
 			def response = RestAssuredMockMvc.post("/triggers/delete_book")
 		then:
-			response.statusCode == 200
+			response.statusCode == 200
 		and:
-			1 * stubRunning.trigger('delete_book')
+			1 * stubRunning.trigger('delete_book')
 	}
 
 	def 'should trigger a messaging label for a stub with [#stubId] ivy notation'() {
@@ -721,9 +721,9 @@ the Stub Runner server. It will be available at port 8750<
 		when:
 			def response = RestAssuredMockMvc.post("/triggers/$stubId/delete_book")
 		then:
-			response.statusCode == 200
+			response.statusCode == 200
 		and:
-			1 * stubRunning.trigger(stubId, 'delete_book')
+			1 * stubRunning.trigger(stubId, 'delete_book')
 		where:
 			stubId << ['org.springframework.cloud.contract.verifier.stubs:bootService:stubs', 'org.springframework.cloud.contract.verifier.stubs:bootService', 'bootService']
 	}
@@ -748,10 +748,10 @@ the Stub Runner server. It will be available at port 8750<
  of testing scenarios.

The problem with this approach is such that if you’re doing microservices most likely you’re using a service discovery tool. Stub Runner Boot allows you to solve this issue by starting the required stubs and register them in a service discovery tool. Let’s take a look at an example of - such a setup with Eureka. Let’s assume that Eureka was already running.

@SpringBootApplication
-@EnableStubRunnerServer
-@EnableEurekaClient
-@AutoConfigureStubRunner
+ such a setup with Eureka. Let’s assume that Eureka was already running.

@SpringBootApplication
+@EnableStubRunnerServer
+@EnableEurekaClient
+@AutoConfigureStubRunner
 public class StubRunnerBootEurekaExample {
 
 	public static void main(String[] args) {
@@ -761,17 +761,17 @@ the Stub Runner server. It will be available at port 8750<
 }

As you can see we want to start a Stub Runner Boot server @EnableStubRunnerServer, enable Eureka client @EnableEurekaClient and we want to have the stub runner feature turned on @AutoConfigureStubRunner.

Now let’s assume that we want to start this application so that the stubs get automatically registered. We can do it by running the app java -jar ${SYSTEM_PROPS} stub-runner-boot-eureka-example.jar where - ${SYSTEM_PROPS} would contain the following list of properties

* -Dstubrunner.repositoryRoot=https://repo.spring.io/snapshot (1)
-* -Dstubrunner.cloud.stubbed.discovery.enabled=false (2)
+ ${SYSTEM_PROPS} would contain the following list of properties

* -Dstubrunner.repositoryRoot=https://repo.spring.io/snapshot (1)
+* -Dstubrunner.cloud.stubbed.discovery.enabled=false (2)
 * -Dstubrunner.ids=org.springframework.cloud.contract.verifier.stubs:loanIssuance,org.
 * springframework.cloud.contract.verifier.stubs:fraudDetectionServer,org.springframework.
-* cloud.contract.verifier.stubs:bootService (3)
+* cloud.contract.verifier.stubs:bootService (3)
 * -Dstubrunner.idsToServiceIds.fraudDetectionServer=
-* someNameThatShouldMapFraudDetectionServer (4)
+* someNameThatShouldMapFraudDetectionServer (4)
 *
-* (1) - we tell Stub Runner where all the stubs reside (2) - we don't want the default
+* (1) - we tell Stub Runner where all the stubs reside (2) - we don't want the default
 * behaviour where the discovery service is stubbed. That's why the stub registration will
-* be picked (3) - we provide a list of stubs to download (4) - we provide a list of

That way your deployed application can send requests to started WireMock servers via the service +* be picked (3) - we provide a list of stubs to download (4) - we provide a list of

That way your deployed application can send requests to started WireMock servers via the service discovery. Most likely points 1-3 could be set by default in application.yml cause they are not likely to change. That way you can provide only the list of stubs to download whenever you start the Stub Runner Boot.

6.7 Stubs Per Consumer

There are cases in which 2 consumers of the same endpoint want to have 2 different responses.

[Tip]Tip

This approach also allows you to immediately know which consumer is using which part of your API. @@ -807,22 +807,22 @@ if it contains the subfolder with name of the consumer in the path only then wil └── foo-consumer ├── bookReturnedForFoo.groovy └── shouldCallFoo.groovy

Being the bar-consumer consumer you can either set the spring.application.name or the stubrunner.consumer-name to bar-consumer -Or set the test as follows:

@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
-@SpringBootTest(properties = ["spring.application.name=bar-consumer"])
-@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers",
+Or set the test as follows:

@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
+@SpringBootTest(properties = ["spring.application.name=bar-consumer"])
+@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers",
 		repositoryRoot = "classpath:m2repo/repository/",
 		stubsMode = StubRunnerProperties.StubsMode.REMOTE,
-		stubsPerConsumer = true)
+		stubsPerConsumer = true)
 class StubRunnerStubsPerConsumerSpec extends Specification {
 ...
 }

Then only the stubs registered under a path that contains the bar-consumer in its name (i.e. those from the -src/test/resources/contracts/bar-consumer/some/contracts/…​ folder) will be allowed to be referenced.

Or set the consumer name explicitly

@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
-@SpringBootTest
-@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers",
+src/test/resources/contracts/bar-consumer/some/contracts/…​ folder) will be allowed to be referenced.

Or set the consumer name explicitly

@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
+@SpringBootTest
+@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers",
 		repositoryRoot = "classpath:m2repo/repository/",
 		consumerName = "foo-consumer",
 		stubsMode = StubRunnerProperties.StubsMode.REMOTE,
-		stubsPerConsumer = true)
+		stubsPerConsumer = true)
 class StubRunnerStubsPerConsumerWithConsumerNameSpec extends Specification {
 ...
 }

Then only the stubs registered under a path that contains the foo-consumer in its name (i.e. those from the @@ -860,9 +860,9 @@ $ STUBRUNNER_REPOSITORY_ROOT=# Run the docker with Stub Runner Boot $ docker run --rm -e "STUBRUNNER_IDS=${STUBRUNNER_IDS}" -e "STUBRUNNER_REPOSITORY_ROOT=${STUBRUNNER_REPOSITORY_ROOT}" -e "STUBRUNNER_STUBS_MODE=REMOTE" -p "${STUBRUNNER_PORT}:${STUBRUNNER_PORT}" -p "9876:9876" springcloud/spring-cloud-contract-stub-runner:"${SC_CONTRACT_DOCKER_VERSION}"

What’s happening is that

  • a standalone Stub Runner application got started
  • it downloaded the stub with coordinates com.example:bookstore:0.0.1.RELEASE:stubs on port 9876
  • it got downloaded from Artifactory running at http://192.168.0.100:8081/artifactory/libs-release-local
  • after a while Stub Runner will be running on port 8083
  • and the stubs will be running at port 9876

On the server side we built a stateful stub. Let’s use curl to assert that the stubs are setup properly.

# let's execute the first request (no response is returned)
-$ curl -H "Content-Type:application/json" -X POST --data '{ "title" : "Title", "genre" : "Genre", "description" : "Description", "author" : "Author", "publisher" : "Publisher", "pages" : 100, "image_url" : "https://d213dhlpdb53mu.cloudfront.net/assets/pivotal-square-logo-41418bd391196c3022f3cd9f3959b3f6d7764c47873d858583384e759c7db435.svg", "buy_url" : "https://pivotal.io" }' http://localhost:9876/api/books
+$ curl -H "Content-Type:application/json" -X POST --data '{ "title" : "Title", "genre" : "Genre", "description" : "Description", "author" : "Author", "publisher" : "Publisher", "pages" : 100, "image_url" : "https://d213dhlpdb53mu.cloudfront.net/assets/pivotal-square-logo-41418bd391196c3022f3cd9f3959b3f6d7764c47873d858583384e759c7db435.svg", "buy_url" : "https://pivotal.io" }' http://localhost:9876/api/books
 # Now time for the second request
-$ curl -X GET http://localhost:9876/api/books
+$ curl -X GET http://localhost:9876/api/books
 # You will receive contents of the JSON
[Important]Important

If you want use the stubs that you have built locally, on your host, then you should pass the environment variable -e STUBRUNNER_STUBS_MODE=LOCAL and mount the volume of your local m2 -v "${HOME}/.m2/:/root/.m2:ro"

\ No newline at end of file diff --git a/2.1.x/multi/multi__spring_cloud_contract_verifier_introduction.html b/2.1.x/multi/multi__spring_cloud_contract_verifier_introduction.html index a73e496f99..fe8bdf7d14 100644 --- a/2.1.x/multi/multi__spring_cloud_contract_verifier_introduction.html +++ b/2.1.x/multi/multi__spring_cloud_contract_verifier_introduction.html @@ -65,10 +65,10 @@ Stub Runner properties, as shown in the following example:

  ids: 'com.example:http-server-dsl:+:stubs:8080'
   repositoryRoot: https://repo.spring.io/libs-snapshot

Now you can annotate your test class with @AutoConfigureStubRunner. In the annotation, provide the group-id and artifact-id values for Spring Cloud Contract Stub Runner to -run the collaborators' stubs for you, as shown in the following example:

@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment=WebEnvironment.NONE)
-@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
-		stubsMode = StubRunnerProperties.StubsMode.LOCAL)
+run the collaborators' stubs for you, as shown in the following example:

@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment=WebEnvironment.NONE)
+@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
+		stubsMode = StubRunnerProperties.StubsMode.LOCAL)
 public class LoanApplicationServiceTests {
[Tip]Tip

Use the REMOTE stubsMode when downloading stubs from an online repository and LOCAL for offline work.

Now, in your integration test, you can receive stubbed versions of HTTP responses or messages that are expected to be emitted by the collaborator service.

2.4.2 A Three-minute Tour

This brief tour walks through using Spring Cloud Contract:

You can find an even more brief tour @@ -84,7 +84,7 @@ org.springframework.cloud.contract.spec.Contract.make { url '/fraudcheck' body([ "client.id": $(regex('[0-9]{10}')), - loanAmount: 99999 + loanAmount: 99999 ]) headers { contentType('application/json') @@ -104,8 +104,8 @@ org.springframework.cloud.contract.spec.Contract.make { method: PUT url: /fraudcheck body: - "client.id": 1234567890 - loanAmount: 99999 + "client.id": 1234567890 + loanAmount: 99999 headers: Content-Type: application/json matchers: @@ -114,12 +114,12 @@ org.springframework.cloud.contract.spec.Contract.make { type: by_regex value: "[0-9]{10}" response: - status: 200 + status: 200 body: fraudCheckStatus: "FRAUD" "rejection.reason": "Amount too high" headers: - Content-Type: application/json;charset=UTF-8

In the case of messaging, you can define:

  • The input and the output messages can be defined (taking into account from and where it + Content-Type: application/json;charset=UTF-8

In the case of messaging, you can define:

  • The input and the output messages can be defined (taking into account from and where it was sent, the message body, and the header).
  • The methods that should be called after the message is received.
  • The methods that, when called, should trigger a message.

The following example shows a Camel messaging contract expressed in Groovy DSL:

			def contractDsl = Contract.make {
 				label 'some_label'
 				input {
@@ -152,7 +152,7 @@ portion of the file:

<extensions>true</extensions>
 </plugin>

Running ./mvnw clean install automatically generates tests that verify the application compliance with the added contracts. By default, the generated tests are under -org.springframework.cloud.contract.verifier.tests..

The following example shows a sample auto-generated test for an HTTP contract:

@Test
+org.springframework.cloud.contract.verifier.tests..

The following example shows a sample auto-generated test for an HTTP contract:

@Test
 public void validate_shouldMarkClientAsFraud() throws Exception {
     // given:
         MockMvcRequestSpecification request = given()
@@ -164,7 +164,7 @@ compliance with the added contracts. By default, the generated tests are under
                 .put("/fraudcheck");
 
     // then:
-        assertThat(response.statusCode()).isEqualTo(200);
+        assertThat(response.statusCode()).isEqualTo(200);
         assertThat(response.header("Content-Type")).matches("application/vnd.fraud.v1.json.*");
     // and:
         DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
@@ -213,18 +213,18 @@ contain all the setup necessary to run them (for example, 
 setup or messaging test setup).

Once the implementation and the test base class are in place, the tests pass, and both the application and the stub artifacts are built and installed in the local Maven repository. Information about installing the stubs jar to the local repository appears in the logs, as -shown in the following example:

[INFO] --- spring-cloud-contract-maven-plugin:1.0.0.BUILD-SNAPSHOT:generateStubs (default-generateStubs) @ http-server ---
-[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar
+shown in the following example:

[INFO] --- spring-cloud-contract-maven-plugin:1.0.0.BUILD-SNAPSHOT:generateStubs (default-generateStubs) @ http-server ---
+[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar
 [INFO]
-[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ http-server ---
-[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar
+[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ http-server ---
+[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar
 [INFO]
-[INFO] --- spring-boot-maven-plugin:1.5.5.BUILD-SNAPSHOT:repackage (default) @ http-server ---
+[INFO] --- spring-boot-maven-plugin:1.5.5.BUILD-SNAPSHOT:repackage (default) @ http-server ---
 [INFO]
-[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ http-server ---
-[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.jar
-[INFO] Installing /some/path/http-server/pom.xml to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.pom
-[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar

You can now merge the changes and publish both the application and the stub artifacts +[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ http-server --- +[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.jar +[INFO] Installing /some/path/http-server/pom.xml to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.pom +[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar

You can now merge the changes and publish both the application and the stub artifacts in an online repository.

Docker Project

In order to enable working with contracts while creating applications in non-JVM technologies, the springcloud/spring-cloud-contract Docker image has been created. It contains a project that automatically generates tests for HTTP contracts and executes them @@ -245,20 +245,20 @@ Runner properties, as shown in the following example:

  ids: 'com.example:http-server-dsl:+:stubs:8080'
   repositoryRoot: https://repo.spring.io/libs-snapshot

Now you can annotate your test class with @AutoConfigureStubRunner. In the annotation, provide the group-id and artifact-id for Spring Cloud Contract Stub Runner to run -the collaborators' stubs for you, as shown in the following example:

@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment=WebEnvironment.NONE)
-@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
-		stubsMode = StubRunnerProperties.StubsMode.LOCAL)
+the collaborators' stubs for you, as shown in the following example:

@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment=WebEnvironment.NONE)
+@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
+		stubsMode = StubRunnerProperties.StubsMode.LOCAL)
 public class LoanApplicationServiceTests {
[Tip]Tip

Use the REMOTE stubsMode when downloading stubs from an online repository and LOCAL for offline work.

In your integration test, you can receive stubbed versions of HTTP responses or messages that are expected to be emitted by the collaborator service. You can see entries similar -to the following in the build logs:

2016-07-19 14:22:25.403  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Desired version is + - will try to resolve the latest version
-2016-07-19 14:22:25.438  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved version is 0.0.1-SNAPSHOT
-2016-07-19 14:22:25.439  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolving artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT using remote repositories []
-2016-07-19 14:22:25.451  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar
-2016-07-19 14:22:25.465  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacking stub from JAR [URI: file:/path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar]
-2016-07-19 14:22:25.475  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacked file to [/var/folders/0p/xwq47sq106x1_g3dtv6qfm940000gq/T/contracts100276532569594265]
-2016-07-19 14:22:27.737  INFO 41050 --- [           main] o.s.c.c.stubrunner.StubRunnerExecutor    : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server:0.0.1-SNAPSHOT:stubs=8080}]

2.4.3 Defining the Contract

As consumers of services, we need to define what exactly we want to achieve. We need to +to the following in the build logs:

2016-07-19 14:22:25.403  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Desired version is + - will try to resolve the latest version
+2016-07-19 14:22:25.438  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved version is 0.0.1-SNAPSHOT
+2016-07-19 14:22:25.439  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolving artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT using remote repositories []
+2016-07-19 14:22:25.451  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar
+2016-07-19 14:22:25.465  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacking stub from JAR [URI: file:/path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar]
+2016-07-19 14:22:25.475  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacked file to [/var/folders/0p/xwq47sq106x1_g3dtv6qfm940000gq/T/contracts100276532569594265]
+2016-07-19 14:22:27.737  INFO 41050 --- [           main] o.s.c.c.stubrunner.StubRunnerExecutor    : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server:0.0.1-SNAPSHOT:stubs=8080}]

2.4.3 Defining the Contract

As consumers of services, we need to define what exactly we want to achieve. We need to formulate our expectations. That is why we write contracts.

Assume that you want to send a request containing the ID of a client company and the amount it wants to borrow from us. You also want to send it to the /fraudcheck url via the PUT method.

Groovy DSL.  @@ -286,7 +286,7 @@ org.springframework.cloud.contract.spec.Contract.make { url '/fraudcheck' // (3) body([ // (4) "client.id": $(regex('[0-9]{10}')), - loanAmount : 99999 + loanAmount : 99999 ]) headers { // (5) contentType('application/json') @@ -392,16 +392,16 @@ response: # (7) You get a running WireMock instance/Messaging route that simulates the service. You would like to feed that instance with a proper stub definition.

At some point in time, you need to send a request to the Fraud Detection service.

ResponseEntity<FraudServiceResponse> response = restTemplate.exchange(
 		"http://localhost:" + port + "/fraudcheck", HttpMethod.PUT,
-		new HttpEntity<>(request, httpHeaders), FraudServiceResponse.class);

Annotate your test class with @AutoConfigureStubRunner. In the annotation provide the group id and artifact id for the Stub Runner to download stubs of your collaborators.

@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment = WebEnvironment.NONE)
-@AutoConfigureStubRunner(ids = {
-		"com.example:http-server-dsl:+:stubs:6565" }, stubsMode = StubRunnerProperties.StubsMode.LOCAL)
+		new HttpEntity<>(request, httpHeaders), FraudServiceResponse.class);

Annotate your test class with @AutoConfigureStubRunner. In the annotation provide the group id and artifact id for the Stub Runner to download stubs of your collaborators.

@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.NONE)
+@AutoConfigureStubRunner(ids = {
+		"com.example:http-server-dsl:+:stubs:6565" }, stubsMode = StubRunnerProperties.StubsMode.LOCAL)
 public class LoanApplicationServiceTests {

After that, during the tests, Spring Cloud Contract automatically finds the stubs (simulating the real service) in the Maven repository and exposes them on a configured (or random) port.

2.4.5 Server Side

Since you are developing your stub, you need to be sure that it actually resembles your concrete implementation. You cannot have a situation where your stub acts in one way and your application behaves in a different way, especially in production.

To ensure that your application behaves the way you define in your stub, tests are -generated from the stub you provide.

The autogenerated test looks, more or less, like this:

@Test
+generated from the stub you provide.

The autogenerated test looks, more or less, like this:

@Test
 public void validate_shouldMarkClientAsFraud() throws Exception {
     // given:
         MockMvcRequestSpecification request = given()
@@ -413,7 +413,7 @@ generated from the stub you provide.

The autogenerated test looks, more or .put("/fraudcheck"); // then: - assertThat(response.statusCode()).isEqualTo(200); + assertThat(response.statusCode()).isEqualTo(200); assertThat(response.header("Content-Type")).matches("application/vnd.fraud.v1.json.*"); // and: DocumentContext parsedJson = JsonPath.parse(response.getBody().asString()); @@ -490,11 +490,11 @@ following section to your build:

Maven.  maven { url "https://repo.spring.io/milestone" } maven { url "https://repo.spring.io/release" } }

-

2.5.2 Consumer side (Loan Issuance)

As a developer of the Loan Issuance service (a consumer of the Fraud Detection server), you might do the following steps:

  1. Start doing TDD by writing a test for your feature.
  2. Write the missing implementation.
  3. Clone the Fraud Detection service repository locally.
  4. Define the contract locally in the repo of Fraud Detection service.
  5. Add the Spring Cloud Contract Verifier plugin.
  6. Run the integration tests.
  7. File a pull request.
  8. Create an initial implementation.
  9. Take over the pull request.
  10. Write the missing implementation.
  11. Deploy your app.
  12. Work online.

Start doing TDD by writing a test for your feature.

@Test
+

2.5.2 Consumer side (Loan Issuance)

As a developer of the Loan Issuance service (a consumer of the Fraud Detection server), you might do the following steps:

  1. Start doing TDD by writing a test for your feature.
  2. Write the missing implementation.
  3. Clone the Fraud Detection service repository locally.
  4. Define the contract locally in the repo of Fraud Detection service.
  5. Add the Spring Cloud Contract Verifier plugin.
  6. Run the integration tests.
  7. File a pull request.
  8. Create an initial implementation.
  9. Take over the pull request.
  10. Write the missing implementation.
  11. Deploy your app.
  12. Work online.

Start doing TDD by writing a test for your feature.

@Test
 public void shouldBeRejectedDueToAbnormalLoanAmount() {
 	// given:
 	LoanApplication application = new LoanApplication(new Client("1234567890"),
-			99999);
+			99999);
 	// when:
 	LoanApplicationResult loanApplication = service.loanApplication(application);
 	// then:
@@ -536,7 +536,7 @@ org.springframework.cloud.contract.spec.Contract.make {
 		url '/fraudcheck' // (3)
 		body([ // (4)
 			   "client.id": $(regex('[0-9]{10}')),
-			   loanAmount : 99999
+			   loanAmount : 99999
 		])
 		headers { // (5)
 			contentType('application/json')
@@ -673,18 +673,18 @@ First, add the Spring Cloud Contract BOM.

</plugin>

Since the plugin was added, you get the Spring Cloud Contract Verifier features which, from the provided contracts:

  • generate and run tests
  • produce and install stubs

You do not want to generate tests since you, as the consumer, want only to play with the stubs. You need to skip the test generation and execution. When you execute:

$ cd local-http-server-repo
-$ ./mvnw clean install -DskipTests

In the logs, you see something like this:

[INFO] --- spring-cloud-contract-maven-plugin:1.0.0.BUILD-SNAPSHOT:generateStubs (default-generateStubs) @ http-server ---
-[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar
+$ ./mvnw clean install -DskipTests

In the logs, you see something like this:

[INFO] --- spring-cloud-contract-maven-plugin:1.0.0.BUILD-SNAPSHOT:generateStubs (default-generateStubs) @ http-server ---
+[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar
 [INFO]
-[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ http-server ---
-[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar
+[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ http-server ---
+[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar
 [INFO]
-[INFO] --- spring-boot-maven-plugin:1.5.5.BUILD-SNAPSHOT:repackage (default) @ http-server ---
+[INFO] --- spring-boot-maven-plugin:1.5.5.BUILD-SNAPSHOT:repackage (default) @ http-server ---
 [INFO]
-[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ http-server ---
-[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.jar
-[INFO] Installing /some/path/http-server/pom.xml to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.pom
-[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar

The following line is extremely important:

[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar

It confirms that the stubs of the http-server have been installed in the local +[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ http-server --- +[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.jar +[INFO] Installing /some/path/http-server/pom.xml to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.pom +[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar

The following line is extremely important:

[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar

It confirms that the stubs of the http-server have been installed in the local repository.

Run the integration tests.

In order to profit from the Spring Cloud Contract Stub Runner functionality of automatic stub downloading, you must do the following in your consumer side project (Loan Application service):

Add the Spring Cloud Contract BOM:

<dependencyManagement>
@@ -704,23 +704,23 @@ Application service):

Add the Spring Cloud Co </dependency>

Annotate your test class with @AutoConfigureStubRunner. In the annotation, provide the group-id and artifact-id for the Stub Runner to download the stubs of your collaborators. (Optional step) Because you’re playing with the collaborators offline, you -can also provide the offline work switch (StubRunnerProperties.StubsMode.LOCAL).

@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment = WebEnvironment.NONE)
-@AutoConfigureStubRunner(ids = {
-		"com.example:http-server-dsl:+:stubs:6565" }, stubsMode = StubRunnerProperties.StubsMode.LOCAL)
-public class LoanApplicationServiceTests {

Now, when you run your tests, you see something like this:

2016-07-19 14:22:25.403  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Desired version is + - will try to resolve the latest version
-2016-07-19 14:22:25.438  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved version is 0.0.1-SNAPSHOT
-2016-07-19 14:22:25.439  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolving artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT using remote repositories []
-2016-07-19 14:22:25.451  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar
-2016-07-19 14:22:25.465  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacking stub from JAR [URI: file:/path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar]
-2016-07-19 14:22:25.475  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacked file to [/var/folders/0p/xwq47sq106x1_g3dtv6qfm940000gq/T/contracts100276532569594265]
-2016-07-19 14:22:27.737  INFO 41050 --- [           main] o.s.c.c.stubrunner.StubRunnerExecutor    : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server:0.0.1-SNAPSHOT:stubs=8080}]

This output means that Stub Runner has found your stubs and started a server for your app +can also provide the offline work switch (StubRunnerProperties.StubsMode.LOCAL).

@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.NONE)
+@AutoConfigureStubRunner(ids = {
+		"com.example:http-server-dsl:+:stubs:6565" }, stubsMode = StubRunnerProperties.StubsMode.LOCAL)
+public class LoanApplicationServiceTests {

Now, when you run your tests, you see something like this:

2016-07-19 14:22:25.403  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Desired version is + - will try to resolve the latest version
+2016-07-19 14:22:25.438  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved version is 0.0.1-SNAPSHOT
+2016-07-19 14:22:25.439  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolving artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT using remote repositories []
+2016-07-19 14:22:25.451  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar
+2016-07-19 14:22:25.465  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacking stub from JAR [URI: file:/path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar]
+2016-07-19 14:22:25.475  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacked file to [/var/folders/0p/xwq47sq106x1_g3dtv6qfm940000gq/T/contracts100276532569594265]
+2016-07-19 14:22:27.737  INFO 41050 --- [           main] o.s.c.c.stubrunner.StubRunnerExecutor    : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server:0.0.1-SNAPSHOT:stubs=8080}]

This output means that Stub Runner has found your stubs and started a server for your app with group id com.example, artifact id http-server with version 0.0.1-SNAPSHOT of the stubs and with stubs classifier on port 8080.

File a pull request.

What you have done until now is an iterative process. You can play around with the contract, install it locally, and work on the consumer side until the contract works as you wish.

Once you are satisfied with the results and the test passes, publish a pull request to -the server side. Currently, the consumer side work is done.

2.5.3 Producer side (Fraud Detection server)

As a developer of the Fraud Detection server (a server to the Loan Issuance service):

Create an initial implementation.

As a reminder, you can see the initial implementation here:

@RequestMapping(value = "/fraudcheck", method = PUT)
-public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) {
+the server side. Currently, the consumer side work is done.

2.5.3 Producer side (Fraud Detection server)

As a developer of the Fraud Detection server (a server to the Loan Issuance service):

Create an initial implementation.

As a reminder, you can see the initial implementation here:

@RequestMapping(value = "/fraudcheck", method = PUT)
+public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) {
 return new FraudCheckResult(FraudCheckStatus.OK, NO_REASON);
 }

Take over the pull request.

$ git checkout -b contract-change-pr master
 $ git pull https://your-git-server.com/server-side-fork.git contract-change-pr

You must add the dependencies needed by the autogenerated tests:

<dependency>
@@ -766,7 +766,7 @@ start the server side FraudDetectionController.

public class FraudBase { - @Before + @Before public void setup() { RestAssuredMockMvc.standaloneSetup(new FraudDetectionController(), new FraudStatsController(stubbedStatsProvider())); @@ -776,11 +776,11 @@ start the server side FraudDetectionController.

return fraudType -> { switch (fraudType) { case DRUNKS: - return 100; + return 100; case ALL: - return 200; + return 200; } - return 0; + return 0; }; } @@ -791,9 +791,9 @@ start the server side FraudDetectionController.

}

Now, if you run the ./mvnw clean install, you get something like this:

Results :
 
 Tests in error:
-  ContractVerifierTest.validate_shouldMarkClientAsFraud:32 » IllegalState Parsed...

This error occurs because you have a new contract from which a test was generated and it + ContractVerifierTest.validate_shouldMarkClientAsFraud:32 » IllegalState Parsed...

This error occurs because you have a new contract from which a test was generated and it failed since you have not implemented the feature. The auto-generated test would look -like this:

@Test
+like this:

@Test
 public void validate_shouldMarkClientAsFraud() throws Exception {
     // given:
         MockMvcRequestSpecification request = given()
@@ -805,7 +805,7 @@ like this:

"/fraudcheck");
 
     // then:
-        assertThat(response.statusCode()).isEqualTo(200);
+        assertThat(response.statusCode()).isEqualTo(200);
         assertThat(response.header("Content-Type")).matches("application/vnd.fraud.v1.json.*");
     // and:
         DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
@@ -818,8 +818,8 @@ in the form of a test. This test sends a request to our own application with the
 headers, and body defined in the contract. It also is expecting precisely defined values
 in the response. In other words, you have the red part of red, green, and
 refactor. It is time to convert the red into the green.

Write the missing implementation.

Because you know the expected input and expected output, you can write the missing -implementation:

@RequestMapping(value = "/fraudcheck", method = PUT)
-public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) {
+implementation:

@RequestMapping(value = "/fraudcheck", method = PUT)
+public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) {
 if (amountGreaterThanThreshold(fraudCheck)) {
 	return new FraudCheckResult(FraudCheckStatus.FRAUD, AMOUNT_TOO_HIGH);
 }
diff --git a/2.1.x/multi/multi__spring_cloud_contract_verifier_messaging.html b/2.1.x/multi/multi__spring_cloud_contract_verifier_messaging.html
index bc9cf3db58..46808027a0 100644
--- a/2.1.x/multi/multi__spring_cloud_contract_verifier_messaging.html
+++ b/2.1.x/multi/multi__spring_cloud_contract_verifier_messaging.html
@@ -19,12 +19,12 @@ work.

ContractVerifierMessageExchange to send and receive messages that follow the contract. Then add @AutoConfigureMessageVerifier to your test. -Here’s an example:

@RunWith(SpringTestRunner.class)
-@SpringBootTest
-@AutoConfigureMessageVerifier
+Here’s an example:

@RunWith(SpringTestRunner.class)
+@SpringBootTest
+@AutoConfigureMessageVerifier
 public static class MessagingContractTests {
 
-  @Autowired
+  @Autowired
   private MessageVerifier verifier;
   ...
 }
[Note]Note

If your tests require stubs as well, then @AutoConfigureStubRunner includes the diff --git a/2.1.x/multi/multi__spring_cloud_contract_verifier_setup.html b/2.1.x/multi/multi__spring_cloud_contract_verifier_setup.html index 82e32a106e..c1792e1fc5 100644 --- a/2.1.x/multi/multi__spring_cloud_contract_verifier_setup.html +++ b/2.1.x/multi/multi__spring_cloud_contract_verifier_setup.html @@ -153,7 +153,7 @@ endpoint, which should be verified.

void isProperCorrelationId(Integer correlationId) {
-		assert correlationId == 123456
+		assert correlationId == 123456
 	}
 
 	void isEmpty(String value) {
@@ -192,20 +192,20 @@ via contractsProperties method e.g. 

4.1.14 Spring Cloud Contract Verifier on the Consumer Side

In a consuming service, you need to configure the Spring Cloud Contract Verifier plugin in exactly the same way as in case of provider. If you do not want to use Stub Runner then you need to copy contracts stored in src/test/resources/contracts and generate -WireMock JSON stubs using:

./gradlew generateClientStubs
[Note]Note

The stubsOutputDir option has to be set for stub generation to work.

When present, JSON stubs can be used in automated tests of consuming a service.

@ContextConfiguration(loader == SpringApplicationContextLoader, classes == Application)
+WireMock JSON stubs using:

./gradlew generateClientStubs
[Note]Note

The stubsOutputDir option has to be set for stub generation to work.

When present, JSON stubs can be used in automated tests of consuming a service.

@ContextConfiguration(loader == SpringApplicationContextLoader, classes == Application)
 class LoanApplicationServiceSpec extends Specification {
 
- @ClassRule
- @Shared
+ @ClassRule
+ @Shared
  WireMockClassRule wireMockRule == new WireMockClassRule()
 
- @Autowired
+ @Autowired
  LoanApplicationService sut
 
  def 'should successfully apply for loan'() {
    given:
  	LoanApplication application =
-			new LoanApplication(client: new Client(clientPesel: '12345678901'), amount: 123.123)
+			new LoanApplication(client: new Client(clientPesel: '12345678901'), amount: 123.123)
    when:
 	LoanApplicationResult loanApplication == sut.loanApplication(application)
    then:
@@ -253,13 +253,13 @@ Assured 2.x by adding it to the plugins classpath, as shown here:

2.5.0</version>
+           <version>2.5.0</version>
            <scope>compile</scope>
         </dependency>
         <dependency>
            <groupId>com.jayway.restassured</groupId>
            <artifactId>spring-mock-mvc</artifactId>
-           <version>2.5.0</version>
+           <version>2.5.0</version>
            <scope>compile</scope>
         </dependency>
     </dependencies>
@@ -271,13 +271,13 @@ Assured 2.x by adding it to the plugins classpath, as shown here:

2.5.0</version>
+       <version>2.5.0</version>
        <scope>test</scope>
     </dependency>
     <dependency>
        <groupId>com.jayway.restassured</groupId>
        <artifactId>spring-mock-mvc</artifactId>
-       <version>2.5.0</version>
+       <version>2.5.0</version>
        <scope>test</scope>
     </dependency>
 </dependencies>

That way, the plugin automatically sees that Rest Assured 3.x is present on the classpath @@ -409,14 +409,14 @@ endpoint, which should be verified.

import org.springframework.test.context.junit4.SpringRunner;
 import org.springframework.web.context.WebApplicationContext;
 
-@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SomeConfig.class, properties="some=property")
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SomeConfig.class, properties="some=property")
 public abstract class BaseTestClass {
 
-	@Autowired
+	@Autowired
 	WebApplicationContext context;
 
-	@Before
+	@Before
 	public void setup() {
 		RestAssuredMockMvc.webAppContextSetup(this.context);
 	}
@@ -430,14 +430,14 @@ similarly, as you might find in regular integration tests.

import org.springframework.test.context.junit4.SpringRunner;
 import org.springframework.web.context.WebApplicationContext;
 
-@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SomeConfig.class, properties="some=property")
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SomeConfig.class, properties="some=property")
 public abstract class BaseTestClass {
 
-	@LocalServerPort
+	@LocalServerPort
 	int port;
 
-	@Before
+	@Before
 	public void setup() {
 		RestAssured.baseURI = "http://localhost:" + this.port;
 	}
@@ -544,13 +544,13 @@ goal. Example:

</plugin>

Under Section 10.6, “Using the SCM Stub Downloader” you can find all possible configuration options that you can pass either via the <configuration><contractProperties> map, a system property -or an environment variable.

4.2.12 Maven Plugin and STS

If you see the following exception while using STS:

STS Exception

When you click on the error marker you should see something like this:

 plugin:1.1.0.M1:convert:default-convert:process-test-resources) org.apache.maven.plugin.PluginExecutionException: Execution default-convert of goal org.springframework.cloud:spring-
- cloud-contract-maven-plugin:1.1.0.M1:convert failed. at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:145) at
- org.eclipse.m2e.core.internal.embedder.MavenImpl.execute(MavenImpl.java:331) at org.eclipse.m2e.core.internal.embedder.MavenImpl$11.call(MavenImpl.java:1362) at
+or an environment variable.

4.2.12 Maven Plugin and STS

If you see the following exception while using STS:

STS Exception

When you click on the error marker you should see something like this:

 plugin:1.1.0.M1:convert:default-convert:process-test-resources) org.apache.maven.plugin.PluginExecutionException: Execution default-convert of goal org.springframework.cloud:spring-
+ cloud-contract-maven-plugin:1.1.0.M1:convert failed. at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:145) at
+ org.eclipse.m2e.core.internal.embedder.MavenImpl.execute(MavenImpl.java:331) at org.eclipse.m2e.core.internal.embedder.MavenImpl$11.call(MavenImpl.java:1362) at
 ...
- org.eclipse.core.internal.jobs.Worker.run(Worker.java:55) Caused by: java.lang.NullPointerException at
- org.eclipse.m2e.core.internal.builder.plexusbuildapi.EclipseIncrementalBuildContext.hasDelta(EclipseIncrementalBuildContext.java:53) at
- org.sonatype.plexus.build.incremental.ThreadBuildContext.hasDelta(ThreadBuildContext.java:59) at

In order to fix this issue, provide the following section in your pom.xml:

<build>
+ org.eclipse.core.internal.jobs.Worker.run(Worker.java:55) Caused by: java.lang.NullPointerException at
+ org.eclipse.m2e.core.internal.builder.plexusbuildapi.EclipseIncrementalBuildContext.hasDelta(EclipseIncrementalBuildContext.java:53) at
+ org.sonatype.plexus.build.incremental.ThreadBuildContext.hasDelta(ThreadBuildContext.java:59) at

In order to fix this issue, provide the following section in your pom.xml:

<build>
     <pluginManagement>
         <plugins>
             <!--This plugin's configuration is used to store Eclipse m2e settings
@@ -590,13 +590,13 @@ Please refer to the example below:

If yo Surefire plugin setup, like in the following example:

4.3 Stubs and Transitive Dependencies

The Maven and Gradle plugin that add the tasks that create the stubs jar for you. One problem that arises is that, when reusing the stubs, you can mistakenly import all of that stub’s dependencies. When building a Maven artifact, even though you have a couple -of different jars, all of them share one pom:

├── github-webhook-0.0.1.BUILD-20160903.075506-1-stubs.jar
-├── github-webhook-0.0.1.BUILD-20160903.075506-1-stubs.jar.sha1
-├── github-webhook-0.0.1.BUILD-20160903.075655-2-stubs.jar
-├── github-webhook-0.0.1.BUILD-20160903.075655-2-stubs.jar.sha1
-├── github-webhook-0.0.1.BUILD-SNAPSHOT.jar
-├── github-webhook-0.0.1.BUILD-SNAPSHOT.pom
-├── github-webhook-0.0.1.BUILD-SNAPSHOT-stubs.jar
+of different jars, all of them share one pom:

├── github-webhook-0.0.1.BUILD-20160903.075506-1-stubs.jar
+├── github-webhook-0.0.1.BUILD-20160903.075506-1-stubs.jar.sha1
+├── github-webhook-0.0.1.BUILD-20160903.075655-2-stubs.jar
+├── github-webhook-0.0.1.BUILD-20160903.075655-2-stubs.jar.sha1
+├── github-webhook-0.0.1.BUILD-SNAPSHOT.jar
+├── github-webhook-0.0.1.BUILD-SNAPSHOT.pom
+├── github-webhook-0.0.1.BUILD-SNAPSHOT-stubs.jar
 ├── ...
 └── ...

There are three possibilities of working with those dependencies so as not to have any issues with transitive dependencies:

  • Mark all application dependencies as optional
  • Create a separate artifactid for the stubs
  • Exclude dependencies on the consumer side

Mark all application dependencies as optional

If, in the github-webhook application, you mark all of your dependencies as optional, diff --git a/2.1.x/multi/multi__spring_cloud_contract_wiremock.html b/2.1.x/multi/multi__spring_cloud_contract_wiremock.html index cef802f7be..9f41cedc30 100644 --- a/2.1.x/multi/multi__spring_cloud_contract_wiremock.html +++ b/2.1.x/multi/multi__spring_cloud_contract_wiremock.html @@ -8,23 +8,23 @@ the default with spring-boot-starter-web), you can spring-cloud-starter-contract-stub-runner to your classpath and add @AutoConfigureWireMock in order to be able to use Wiremock in your tests. Wiremock runs as a stub server and you can register stub behavior using a Java API or via static JSON declarations as part of -your test. The following code shows an example:

@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
-@AutoConfigureWireMock(port = 0)
+your test. The following code shows an example:

@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
+@AutoConfigureWireMock(port = 0)
 public class WiremockForDocsTests {
 
 	// A service that calls out over HTTP
-	@Autowired
+	@Autowired
 	private Service service;
 
-	@Before
+	@Before
 	public void setup() {
 		this.service.setBase("http://localhost:"
 				+ this.environment.getProperty("wiremock.server.port"));
 	}
 
 	// Using the WireMock APIs in the normal way:
-	@Test
+	@Test
 	public void contextLoads() throws Exception {
 		// Stubbing WireMock
 		stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
@@ -58,7 +58,7 @@ public class WiremockImportApplicationTests {
 }
[Note]Note

Actually, WireMock always loads mappings from src/test/resources/mappings as well as the custom locations in the stubs attribute. To change this behavior, you can also specify a files root as described in the next section of this document.

If you’re using Spring Cloud Contract’s default stub jars, then your -stubs are stored under /META-INF/group-id/artifact-id/versions/mappings/ folder. If you want to register all stubs from that location, from all embedded JARs, then it’s enough to use the following syntax.

@AutoConfigureWireMock(port = 0, stubs = "classpath*:/META-INF/**/mappings/**/*.json")

11.2 Using Files to Specify the Stub Bodies

WireMock can read response bodies from files on the classpath or the file system. In that +stubs are stored under /META-INF/group-id/artifact-id/versions/mappings/ folder. If you want to register all stubs from that location, from all embedded JARs, then it’s enough to use the following syntax.

@AutoConfigureWireMock(port = 0, stubs = "classpath*:/META-INF/**/mappings/**/*.json")

11.2 Using Files to Specify the Stub Bodies

WireMock can read response bodies from files on the classpath or the file system. In that case, you can see in the JSON DSL that the response has a bodyFileName instead of a (literal) body. The files are resolved relative to a root directory (by default, src/test/resources/__files). To customize this location you can set the files @@ -71,27 +71,27 @@ automatic loading of stubs, because they come from the root location in a subdirectory called "mappings". The value of files has no effect on the stubs loaded explicitly from the stubs attribute.

11.3 Alternative: Using JUnit Rules

For a more conventional WireMock experience, you can use JUnit @Rules to start and stop the server. To do so, use the WireMockSpring convenience class to obtain an Options -instance, as shown in the following example:

@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
+instance, as shown in the following example:

@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
 public class WiremockForDocsClassRuleTests {
 
 	// Start WireMock on some dynamic port
 	// for some reason `dynamicPort()` is not working properly
-	@ClassRule
+	@ClassRule
 	public static WireMockClassRule wiremock = new WireMockClassRule(
 			WireMockSpring.options().dynamicPort());
 
 	// A service that calls out over HTTP to wiremock's port
-	@Autowired
+	@Autowired
 	private Service service;
 
-	@Before
+	@Before
 	public void setup() {
 		this.service.setBase("http://localhost:" + wiremock.port());
 	}
 
 	// Using the WireMock APIs in the normal way:
-	@Test
+	@Test
 	public void contextLoads() throws Exception {
 		// Stubbing WireMock
 		wiremock.stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
@@ -107,21 +107,21 @@ the SSL certificates are not valid (the usual problem with self-installed certif
 The best option is often to re-configure the client to use "http". If that’s not an
 option, you can ask Spring to configure an HTTP client that ignores SSL validation errors
 (do so only for tests, of course).

To make this work with minimum fuss, you need to be using the Spring Boot -RestTemplateBuilder in your app, as shown in the following example:

@Bean
+RestTemplateBuilder in your app, as shown in the following example:

@Bean
 public RestTemplate restTemplate(RestTemplateBuilder builder) {
 	return builder.build();
 }

You need RestTemplateBuilder because the builder is passed through callbacks to initialize it, so the SSL validation can be set up in the client at that point. This happens automatically in your test if you are using the @AutoConfigureWireMock annotation or the stub runner. If you use the JUnit @Rule approach, you need to add the -@AutoConfigureHttpClient annotation as well, as shown in the following example:

@RunWith(SpringRunner.class)
-@SpringBootTest("app.baseUrl=https://localhost:6443")
-@AutoConfigureHttpClient
+@AutoConfigureHttpClient annotation as well, as shown in the following example:

@RunWith(SpringRunner.class)
+@SpringBootTest("app.baseUrl=https://localhost:6443")
+@AutoConfigureHttpClient
 public class WiremockHttpsServerApplicationTests {
 
-	@ClassRule
+	@ClassRule
 	public static WireMockClassRule wiremock = new WireMockClassRule(
-			WireMockSpring.options().httpsPort(6443));
+			WireMockSpring.options().httpsPort(6443));
 ...
 }

If you are using spring-boot-starter-test, you have the Apache HTTP client on the classpath and it is selected by the RestTemplateBuilder and configured to ignore SSL @@ -129,17 +129,17 @@ errors. If you use the default java.net client, you won’t do any harm). There is no support currently for other clients, but it may be added in future releases.

To disable the custom RestTemplateBuilder, set the wiremock.rest-template-ssl-enabled property to false.

11.5 WireMock and Spring MVC Mocks

Spring Cloud Contract provides a convenience class that can load JSON WireMock stubs into -a Spring MockRestServiceServer. The following code shows an example:

@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment = WebEnvironment.NONE)
+a Spring MockRestServiceServer. The following code shows an example:

@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.NONE)
 public class WiremockForDocsMockServerApplicationTests {
 
-	@Autowired
+	@Autowired
 	private RestTemplate restTemplate;
 
-	@Autowired
+	@Autowired
 	private Service service;
 
-	@Test
+	@Test
 	public void contextLoads() throws Exception {
 		// will read stubs classpath
 		MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate)
@@ -162,10 +162,10 @@ Spring Boot embedded servers, and Wiremock itself has "native" support for a par
 version of Jetty (currently 9.2). To use the native Jetty, you need to add the native
 Wiremock dependencies and exclude the Spring Boot container (if there is one).

11.6 Customization of WireMock configuration

You can register a bean of org.springframework.cloud.contract.wiremock.WireMockConfigurationCustomizer type in order to customize the WireMock configuration (e.g. add custom transformers). -Example:

		@Bean
+Example:

		@Bean
 		WireMockConfigurationCustomizer optionsCustomizer() {
 			return new WireMockConfigurationCustomizer() {
-				@Override
+				@Override
 				public void customize(WireMockConfiguration options) {
 // perform your customization here
 				}
@@ -176,16 +176,16 @@ or WebTestClient or Rest Assured. At the same time
 generate WireMock stubs by using Spring Cloud Contract WireMock. To do so, write your
 normal REST Docs test cases and use @AutoConfigureRestDocs to have stubs be
 automatically generated in the REST Docs output directory. The following code shows an
-example using MockMvc:

@RunWith(SpringRunner.class)
-@SpringBootTest
-@AutoConfigureRestDocs(outputDir = "target/snippets")
-@AutoConfigureMockMvc
+example using MockMvc:

@RunWith(SpringRunner.class)
+@SpringBootTest
+@AutoConfigureRestDocs(outputDir = "target/snippets")
+@AutoConfigureMockMvc
 public class ApplicationTests {
 
-	@Autowired
+	@Autowired
 	private MockMvc mockMvc;
 
-	@Test
+	@Test
 	public void contextLoads() throws Exception {
 		mockMvc.perform(get("/resource"))
 				.andExpect(content().string("Hello World"))
@@ -193,16 +193,16 @@ example using MockMvc:

WebTestClient (used
-for testing Spring WebFlux applications) would look like this:

@RunWith(SpringRunner.class)
-@SpringBootTest
-@AutoConfigureRestDocs(outputDir = "target/snippets")
-@AutoConfigureWebTestClient
+for testing Spring WebFlux applications) would look like this:

@RunWith(SpringRunner.class)
+@SpringBootTest
+@AutoConfigureRestDocs(outputDir = "target/snippets")
+@AutoConfigureWebTestClient
 public class ApplicationTests {
 
-	@Autowired
+	@Autowired
 	private WebTestClient client;
 
-	@Test
+	@Test
 	public void contextLoads() throws Exception {
 		client.get().uri("/resource").exchange()
 				.expectBody(String.class).isEqualTo("Hello World")
@@ -236,7 +236,7 @@ matchers. If JSON Path is unfamiliar, The WebTestClient version of this test
 has a similar verify() static helper that you insert in the same place.

Instead of the jsonPath and contentType convenience methods, you can also use the WireMock APIs to verify that the request matches the created stub, as shown in the -following example:

@Test
+following example:

@Test
 public void contextLoads() throws Exception {
 	mockMvc.perform(post("/resource")
                .content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
@@ -258,7 +258,7 @@ range of parameters. The above example generates a stub resembling the following
     }]
   },
   "response" : {
-    "status" : 200,
+    "status" : 200,
     "body" : "Hello World",
     "headers" : {
       "X-Application-Context" : "application:-1",
@@ -299,7 +299,7 @@ Contract.make {
         method 'POST'
         url '/foo'
         body('''
-            {"foo": 23 }
+            {"foo": 23 }
         ''')
         headers {
             header('''Accept''', '''application/json''')
diff --git a/2.1.x/multi/multi__using_the_pluggable_architecture.html b/2.1.x/multi/multi__using_the_pluggable_architecture.html
index aaeb73feeb..77fcf95ce9 100644
--- a/2.1.x/multi/multi__using_the_pluggable_architecture.html
+++ b/2.1.x/multi/multi__using_the_pluggable_architecture.html
@@ -8,7 +8,7 @@ can generate tests for other languages) and the way stubs are generated (for exa
 can generate stubs for other HTTP server implementations).

10.1 Custom Contract Converter

The ContractConverter interface lets you register your own implementation of a contract structure converter. The following code listing shows the ContractConverter interface:

package org.springframework.cloud.contract.spec
 
-/**
+/**
  * Converter to be used to convert FROM {@link File} TO {@link Contract}
  * and from {@link Contract} to {@code T}
  *
@@ -16,32 +16,32 @@ structure converter. The following code listing shows the 
  *
  * @author Marcin Grzejszczak
  * @since 1.1.0
- */
+ */
 interface ContractConverter<T> extends ContractStorer<T> {
 
-	/**
+	/**
 	 * Should this file be accepted by the converter. Can use the file extension
 	 * to check if the conversion is possible.
 	 *
 	 * @param file - file to be considered for conversion
 	 * @return - {@code true} if the given implementation can convert the file
-	 */
+	 */
 	boolean isAccepted(File file)
 
-	/**
+	/**
 	 * Converts the given {@link File} to its {@link Contract} representation
 	 *
 	 * @param file - file to convert
 	 * @return - {@link Contract} representation of the file
-	 */
+	 */
 	Collection<Contract> convertFrom(File file)
 
-	/**
+	/**
 	 * Converts the given {@link Contract} to a {@link T} representation
 	 *
 	 * @param contract - the parsed contract
 	 * @return - {@link T} the type to which we do the conversion
-	 */
+	 */
 	T convertTo(Collection<Contract> contract)
 }

Your implementation must define the condition on which it should start the conversion. Also, you must define how to perform that conversion in both directions.

[Important]Important

Once you create your implementation, you must create a @@ -76,7 +76,7 @@ set a metaData entry in the Pact file, with key "body": { "clientId": "1234567890", - "loanAmount": 99999 + "loanAmount": 99999 }, "generators": { "body": { @@ -112,7 +112,7 @@ set a metaData entry in the Pact file, with key "response": { - "status": 200, + "status": 200, "headers": { "Content-Type": "application/vnd.fraud.v1+json;charset=UTF-8" }, @@ -177,7 +177,7 @@ the current Pact version that you use.

Maven. 

Gradle. 

classpath "org.springframework.cloud:spring-cloud-contract-pact:${findProperty('verifierVersion') ?: verifierVersion}"

When you execute the build of your application, a test will be generated. The generated -test might be as follows:

@Test
+test might be as follows:

@Test
 public void validate_shouldMarkClientAsFraud() throws Exception {
 	// given:
 		MockMvcRequestSpecification request = given()
@@ -189,7 +189,7 @@ test might be as follows:

"/fraudcheck");
 
 	// then:
-		assertThat(response.statusCode()).isEqualTo(200);
+		assertThat(response.statusCode()).isEqualTo(200);
 		assertThat(response.header("Content-Type")).matches("application/vnd\\.fraud\\.v1\\+json.*");
 	// and:
 		DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
@@ -214,7 +214,7 @@ test might be as follows:

"response" : {
-    "status" : 200,
+    "status" : 200,
     "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}",
     "headers" : {
       "Content-Type" : "application/vnd.fraud.v1+json;charset=UTF-8"
@@ -239,14 +239,14 @@ following code listing shows the SingleTestGeneratorimport org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
 import org.springframework.cloud.contract.verifier.file.ContractMetadata
 
-/**
+/**
  * Builds a single test.
  *
  * @since 1.1.0
- */
+ */
 trait SingleTestGenerator {
 
-	/**
+	/**
 	 * Creates contents of a single test class in which all test scenarios from
 	 * the contract metadata should be placed.
 	 *
@@ -257,12 +257,12 @@ trait SingleTestGenerator {
 	 * @param includedDirectoryRelativePath - relative path to the included directory
 	 * @return contents of a single test class
 	 * @deprecated use{@link SingleTestGenerator#buildClass(ContractVerifierConfigProperties, Collection, String, GeneratedClassData)}
-	 */
-	@Deprecated
+	 */
+	@Deprecated
 	abstract String buildClass(ContractVerifierConfigProperties properties,
 			Collection<ContractMetadata> listOfFiles, String className, String classPackage, String includedDirectoryRelativePath)
 
-	/**
+	/**
 	 * Creates contents of a single test class in which all test scenarios from
 	 * the contract metadata should be placed.
 	 *
@@ -271,7 +271,7 @@ trait SingleTestGenerator {
 	 * @param generatedClassData - information about the generated class
 	 * @param includedDirectoryRelativePath - relative path to the included directory
 	 * @return contents of a single test class
-	 */
+	 */
 	String buildClass(ContractVerifierConfigProperties properties,
 			Collection<ContractMetadata> listOfFiles, String includedDirectoryRelativePath, GeneratedClassData generatedClassData) {
 		String className = generatedClassData.className
@@ -280,11 +280,11 @@ trait SingleTestGenerator {
 		return buildClass(properties, listOfFiles, className, classPackage, path)
 	}
 
-	/**
+	/**
 	 * Extension that should be appended to the generated test class. E.g. {@code .java} or {@code .php}
 	 *
 	 * @param properties - properties passed to the plugin
-	 */
+	 */
 	abstract String fileExtension(ContractVerifierConfigProperties properties)
 
 	static class GeneratedClassData {
@@ -310,26 +310,26 @@ own implementation of the StubGenerator interface.
 import org.springframework.cloud.contract.spec.Contract
 import org.springframework.cloud.contract.verifier.file.ContractMetadata
 
-/**
+/**
  * Converts contracts into their stub representation.
  *
  * @since 1.1.0
- */
-@CompileStatic
+ */
+@CompileStatic
 interface StubGenerator {
 
-	/**
+	/**
 	 * @return {@code true} if the converter can handle the file to convert it into a stub.
-	 */
+	 */
 	boolean canHandleFileName(String fileName)
 
-	/**
+	/**
 	 * @return the collection of converted contracts into stubs. One contract can
 	 * result in multiple stubs.
-	 */
+	 */
 	Map<Contract, String> convertContents(String rootName, ContractMetadata content)
 
-	/**
+	/**
 	 * @return the name of the converted stub file. If you have multiple contracts
 	 * in a single file then a prefix will be added to the generated file. If you
 	 * provide the {@link Contract#name} field then that field will override the
@@ -338,7 +338,7 @@ own implementation of the StubGenerator interface.
 	 * Example: name of file with 2 contracts is {@code foo.groovy}, it will be
 	 * converted by the implementation to {@code foo.json}. The recursive file
 	 * converter will create two files {@code 0_foo.json} and {@code 1_foo.json}
-	 */
+	 */
 	String generateOutputFileNameForInput(String inputFileName)
 }

Again, you must provide a spring.factories file, such as the one shown in the following example:

# Stub converters
@@ -357,38 +357,38 @@ HTTP Stub server implementation, which might resemble the following example:

import org.springframework.cloud.contract.stubrunner.HttpServerStub import org.springframework.util.SocketUtils -@Commons +@Commons class MocoHttpServerStub implements HttpServerStub { private boolean started private JsonRunner runner private int port - @Override + @Override int port() { if (!isRunning()) { - return -1 + return -1 } return port } - @Override + @Override boolean isRunning() { return started } - @Override + @Override HttpServerStub start() { return start(SocketUtils.findAvailableTcpPort()) } - @Override + @Override HttpServerStub start(int port) { this.port = port return this } - @Override + @Override HttpServerStub stop() { if (!isRunning()) { return this @@ -397,7 +397,7 @@ HTTP Stub server implementation, which might resemble the following example:

return this } - @Override + @Override HttpServerStub registerMappings(Collection<File> stubFiles) { List<RunnerSetting> settings = stubFiles.findAll { it.name.endsWith("json") } .collect { @@ -418,12 +418,12 @@ HTTP Stub server implementation, which might resemble the following example:

return this } - @Override + @Override String registeredMappings() { return "" } - @Override + @Override boolean isAccepted(File file) { return file.name.endsWith(".json") } @@ -435,10 +435,10 @@ implementation is used. If you provide more than one, the first one on the list class CustomStubDownloaderBuilder implements StubDownloaderBuilder { - @Override + @Override public StubDownloader build(final StubRunnerOptions stubRunnerOptions) { return new StubDownloader() { - @Override + @Override public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar( StubConfiguration config) { File unpackedStubs = retrieveStubs(); diff --git a/2.1.x/multi/multi_contract-dsl.html b/2.1.x/multi/multi_contract-dsl.html index d18b98950c..57c00e4eb8 100644 --- a/2.1.x/multi/multi_contract-dsl.html +++ b/2.1.x/multi/multi_contract-dsl.html @@ -215,7 +215,7 @@ Contract.make { body(fileAsBytes("request.pdf")) } response { - status 200 + status 200 body(fileAsBytes("response.pdf")) headers { contentType(applicationOctetStream()) @@ -251,13 +251,13 @@ response: // with following response after receiving request // specified in "request" part above). response { - status 200 + status 200 //... } // Contract priority, which can be used for overriding // contracts (1 is highest). Priority is optional. - priority 1 + priority 1 }

YAML. 

priority: 8
@@ -280,7 +280,7 @@ same information is mandatory in request definition of the Contract.

Gr response { //... - status 200 + status 200 } }

YAML.  @@ -298,7 +298,7 @@ the recommended way, as doing so makes the tests ho response { //... - status 200 + status 200 } }

YAML.  @@ -321,7 +321,7 @@ the recommended way, as doing so makes the tests ho // If a simple literal is used as value // default matcher function is used (equalTo) - parameter 'limit': 100 + parameter 'limit': 100 // `equalTo` function simply compares passed value // using identity operator (==). @@ -333,11 +333,11 @@ the recommended way, as doing so makes the tests ho // `matching` function tests parameter // against passed regular expression. - parameter 'offset': value(consumer(matching("[0-9]+")), producer(123)) + parameter 'offset': value(consumer(matching("[0-9]+")), producer(123)) // `notMatching` functions tests if parameter // does not match passed regular expression. - parameter 'loginStartsWith': value(consumer(notMatching(".{0,2}")), producer(3)) + parameter 'loginStartsWith': value(consumer(notMatching(".{0,2}")), producer(3)) } } @@ -346,7 +346,7 @@ the recommended way, as doing so makes the tests ho response { //... - status 200 + status 200 } }

YAML.  @@ -422,7 +422,7 @@ response: response { //... - status 200 + status 200 } }

YAML.  @@ -450,7 +450,7 @@ headers: response { //... - status 200 + status 200 } }

YAML.  @@ -473,7 +473,7 @@ cookies: response { //... - status 200 + status 200 } }

YAML.  @@ -537,7 +537,7 @@ parametrization of either fileName or "/multipart"); // then: - assertThat(response.statusCode()).isEqualTo(200);

The WireMock stub is as follows:

			'''
+ assertThat(response.statusCode()).isEqualTo(200);

The WireMock stub is as follows:

			'''
 {
   "request" : {
 	"url" : "/multipart",
@@ -556,7 +556,7 @@ parametrization of either fileName or } ]
   },
   "response" : {
-	"status" : 200,
+	"status" : 200,
 	"transformers" : [ "response-template", "foo-transformer" ]
   }
 }
@@ -603,7 +603,7 @@ for requests that follow a given pattern. Also, you can use regular expressions
 need to use patterns and not exact values both for your test and your server side tests.

The following example shows how to use regular expressions to write a request:

org.springframework.cloud.contract.spec.Contract.make {
 	request {
 		method('GET')
-		url $(consumer(~/\/[0-9]{2}/), producer('/12'))
+		url $(consumer(~/\/[0-9]{2}/), producer('/12'))
 	}
 	response {
 		status OK()
@@ -674,7 +674,7 @@ use in your contracts, as shown in the following example:

protected static final Pattern NON_EMPTY = Pattern.compile(/[\S\s]+/)
 protected static final Pattern NON_BLANK = Pattern.compile(/^\s*\S[\S\s]*/)
 protected static final Pattern ISO8601_WITH_OFFSET = Pattern.
-		compile(/([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.\d{3})?(Z|[+-][01]\d:[0-5]\d)/)
+		compile(/([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.\d{3})?(Z|[+-][01]\d:[0-5]\d)/)
 
 protected static Pattern anyOf(String... values) {
 	return Pattern.compile(values.collect({ "^$it\$" }).join("|"))
@@ -755,7 +755,7 @@ RegexProperty nonEmpty() {
 RegexProperty nonBlank() {
 	return new RegexProperty(NON_BLANK).asString()
 }

In your contract, you can use it as shown in the following example:

Contract dslWithOptionalsInString = Contract.make {
-	priority 1
+	priority 1
 	request {
 		method POST()
 		url '/users/password'
@@ -768,7 +768,7 @@ RegexProperty nonBlank() {
 		)
 	}
 	response {
-		status 404
+		status 404
 		headers {
 			contentType(applicationJson())
 		}
@@ -850,7 +850,7 @@ T anyOf(String... values)

and this is an example of how you can referenc }

8.5.3 Passing Optional Parameters

[Important]Important

This section is valid only for Groovy DSL. Check out the Section 8.5.7, “Dynamic Properties in the Matchers Sections” section for YAML examples of a similar feature.

It is possible to provide optional parameters in your contract. However, you can provide optional parameters only for the following:

  • STUB side of the Request
  • TEST side of the Response

The following example shows how to provide optional parameters:

org.springframework.cloud.contract.spec.Contract.make {
-	priority 1
+	priority 1
 	request {
 		method 'POST'
 		url '/users/password'
@@ -863,7 +863,7 @@ optional parameters only for the following:

    404 + status 404 headers { header 'Content-Type': 'application/json' } @@ -883,7 +883,7 @@ expression that must be present 0 or more times.

    If you use Spock for, the .post("/users/password") then: - response.statusCode == 404 + response.statusCode == 404 response.header('Content-Type') == 'application/json' and: DocumentContext parsedJson = JsonPath.parse(response.body.asString()) @@ -905,13 +905,13 @@ expression that must be present 0 or more times.

    If you use Spock for, the } }, "response" : { - "status" : 404, - "body" : "{\\"code\\":\\"123123\\",\\"message\\":\\"User not found by email == [not.existing@user.com]\\"}", + "status" : 404, + "body" : "{\\"code\\":\\"123123\\",\\"message\\":\\"User not found by email == [not.existing@user.com]\\"}", "headers" : { "Content-Type" : "application/json" } }, - "priority" : 1 + "priority" : 1 } '''

8.5.4 Executing Custom Methods on the Server Side

[Important]Important

This section is valid only for Groovy DSL. Check out the Section 8.5.7, “Dynamic Properties in the Matchers Sections” section for YAML examples of a similar feature.

You can define a method call that executes on the server side during the test. Such a @@ -943,7 +943,7 @@ following code shows an example of the contract portion of the test case:

void isProperCorrelationId(Integer correlationId) { - assert correlationId == 123456 + assert correlationId == 123456 } void isEmpty(String value) { @@ -977,7 +977,7 @@ It should resemble the following code:

"/something");
 
 // then:
- assertThat(response.statusCode()).isEqualTo(200);

8.5.5 Referencing the Request from the Response

The best situation is to provide fixed values, but sometimes you need to reference a + assertThat(response.statusCode()).isEqualTo(200);

8.5.5 Referencing the Request from the Response

The best situation is to provide fixed values, but sometimes you need to reference a request in your response.

If you’re writing contracts using Groovy DSL, you can use the fromRequest() method, which lets you reference a bunch of elements from the HTTP request. You can use the following options:

  • fromRequest().url(): Returns the request URL and query parameters.
  • fromRequest().query(String key): Returns the first query parameter with a given name.
  • fromRequest().query(String key, int index): Returns the nth query parameter with a @@ -1033,7 +1033,7 @@ response: .get("/api/v1/xxxx"); // then: - assertThat(response.statusCode()).isEqualTo(200); + assertThat(response.statusCode()).isEqualTo(200); assertThat(response.header("Authorization")).isEqualTo("foo secret bar"); // and: DocumentContext parsedJson = JsonPath.parse(response.getBody().asString()); @@ -1044,7 +1044,7 @@ response: assertThatJson(parsedJson).field("['param']").isEqualTo("bar"); assertThatJson(parsedJson).field("['paramIndex']").isEqualTo("bar2"); assertThatJson(parsedJson).field("['pathIndex']").isEqualTo("v1"); - assertThatJson(parsedJson).field("['responseBaz']").isEqualTo(5); + assertThatJson(parsedJson).field("['responseBaz']").isEqualTo(5); assertThatJson(parsedJson).field("['responseFoo']").isEqualTo("bar"); assertThatJson(parsedJson).field("['url']").isEqualTo("/api/v1/xxxx?foo=bar&foo=bar2"); assertThatJson(parsedJson).field("['responseBaz2']").isEqualTo("Bla bla bar bla bla");

    As you can see, elements from the request have been properly referenced in the response.

    The generated WireMock stub should resemble the following example:

    {
    @@ -1068,7 +1068,7 @@ response:
         } ]
       },
       "response" : {
    -    "status" : 200,
    +    "status" : 200,
         "body" : "{\"authorization\":\"{{{request.headers.Authorization.[0]}}}\",\"path\":\"{{{request.path}}}\",\"responseBaz\":{{{jsonpath this '$.baz'}}} ,\"param\":\"{{{request.query.foo.[0]}}}\",\"pathIndex\":\"{{{request.path.[1]}}}\",\"responseBaz2\":\"Bla bla {{{jsonpath this '$.foo'}}} bla bla\",\"responseFoo\":\"{{{jsonpath this '$.foo'}}}\",\"authorization2\":\"{{{request.headers.Authorization.[1]}}}\",\"fullBody\":\"{{{escapejsonbody}}}\",\"url\":\"{{{request.url}}}\",\"paramIndex\":\"{{{request.query.foo.[1]}}}\"}",
         "headers" : {
           "Authorization" : "{{{request.headers.Authorization.[0]}}};foo"
    @@ -1086,7 +1086,7 @@ in sending the following response body:

    "authorization2" : "secret2",
       "fullBody" : "{\"foo\":\"bar\",\"baz\":5}",
       "responseFoo" : "bar",
    -  "responseBaz" : 5,
    +  "responseBaz" : 5,
       "responseBaz2" : "Bla bla bar bla bla"
     }
    [Important]Important

    This feature works only with WireMock having a version greater than or equal to 2.5.1. The Spring Cloud Contract Verifier uses WireMock’s @@ -1120,11 +1120,11 @@ org.springframework.cloud.contract.stubrunner.TestCustomYamlContractConverter

    import com.github.tomakehurst.wiremock.extension.Extension -/** +/** * Extension that registers the default transformer and the custom one - */ + */ class TestWireMockExtensions implements WireMockExtensions { - @Override + @Override List<Extension> extensions() { return [ new DefaultResponseTransformer(), @@ -1135,7 +1135,7 @@ org.springframework.cloud.contract.stubrunner.TestCustomYamlContractConverter

    class CustomExtension implements Extension { - @Override + @Override String getName() { return "foo-transformer" } @@ -1179,9 +1179,9 @@ email, url, uuid, iso_date, iso_date_time, iso_time, iso_8601_with_offset, non_e method 'GET' urlPath '/get' body([ - duck : 123, + duck : 123, alpha : 'abc', - number : 123, + number : 123, aBoolean : true, date : '2017-01-01', dateTime : '2017-01-01T01:23:45', @@ -1211,13 +1211,13 @@ email, url, uuid, iso_date, iso_date_time, iso_time, iso_8601_with_offset, non_e response { status OK() body([ - duck : 123, + duck : 123, alpha : 'abc', - number : 123, - positiveInteger : 1234567890, - negativeInteger : -1234567890, - positiveDecimalNumber: 123.4567890, - negativeDecimalNumber: -123.4567890, + number : 123, + positiveInteger : 1234567890, + negativeInteger : -1234567890, + positiveDecimalNumber: 123.4567890, + negativeDecimalNumber: -123.4567890, aBoolean : true, date : '2017-01-01', dateTime : '2017-01-01T01:23:45', @@ -1225,13 +1225,13 @@ email, url, uuid, iso_date, iso_date_time, iso_time, iso_8601_with_offset, non_e valueWithoutAMatcher : 'foo', valueWithTypeMatch : 'string', valueWithMin : [ - 1, 2, 3 + 1, 2, 3 ], valueWithMax : [ - 1, 2, 3 + 1, 2, 3 ], valueWithMinMax : [ - 1, 2, 3 + 1, 2, 3 ], valueWithMinEmpty : [], valueWithMaxEmpty : [], @@ -1262,24 +1262,24 @@ email, url, uuid, iso_date, iso_date_time, iso_time, iso_8601_with_offset, non_e jsonPath('$.valueWithTypeMatch', byType()) jsonPath('$.valueWithMin', byType { // results in verification of size of array (min 1) - minOccurrence(1) + minOccurrence(1) }) jsonPath('$.valueWithMax', byType { // results in verification of size of array (max 3) - maxOccurrence(3) + maxOccurrence(3) }) jsonPath('$.valueWithMinMax', byType { // results in verification of size of array (min 1 & max 3) - minOccurrence(1) - maxOccurrence(3) + minOccurrence(1) + maxOccurrence(3) }) jsonPath('$.valueWithMinEmpty', byType { // results in verification of size of array (min 0) - minOccurrence(0) + minOccurrence(0) }) jsonPath('$.valueWithMaxEmpty', byType { // results in verification of size of array (max 0) - maxOccurrence(0) + maxOccurrence(0) }) // will execute a method `assertThatValueIsANumber` jsonPath('$.duck', byCommand('assertThatValueIsANumber($it)')) @@ -1522,14 +1522,14 @@ separates the autogenerated assertions and the assertion from matchers):

    "/get");
     
     // then:
    - assertThat(response.statusCode()).isEqualTo(200);
    + assertThat(response.statusCode()).isEqualTo(200);
      assertThat(response.header("Content-Type")).matches("application/json.*");
     // and:
      DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
      assertThatJson(parsedJson).field("['valueWithoutAMatcher']").isEqualTo("foo");
     // and:
      assertThat(parsedJson.read("$.duck", String.class)).matches("[0-9]{3}");
    - assertThat(parsedJson.read("$.duck", Integer.class)).isEqualTo(123);
    + assertThat(parsedJson.read("$.duck", Integer.class)).isEqualTo(123);
      assertThat(parsedJson.read("$.alpha", String.class)).matches("[\\p{L}]*");
      assertThat(parsedJson.read("$.alpha", String.class)).isEqualTo("abc");
      assertThat(parsedJson.read("$.number", String.class)).matches("-?(\\d*\\.\\d+|\\d+)");
    @@ -1539,15 +1539,15 @@ separates the autogenerated assertions and the assertion from matchers):

    "$.time", String.class)).matches("(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])");
      assertThat((Object) parsedJson.read("$.valueWithTypeMatch")).isInstanceOf(java.lang.String.class);
      assertThat((Object) parsedJson.read("$.valueWithMin")).isInstanceOf(java.util.List.class);
    - assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMin", java.util.Collection.class)).as("$.valueWithMin").hasSizeGreaterThanOrEqualTo(1);
    + assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMin", java.util.Collection.class)).as("$.valueWithMin").hasSizeGreaterThanOrEqualTo(1);
      assertThat((Object) parsedJson.read("$.valueWithMax")).isInstanceOf(java.util.List.class);
    - assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMax", java.util.Collection.class)).as("$.valueWithMax").hasSizeLessThanOrEqualTo(3);
    + assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMax", java.util.Collection.class)).as("$.valueWithMax").hasSizeLessThanOrEqualTo(3);
      assertThat((Object) parsedJson.read("$.valueWithMinMax")).isInstanceOf(java.util.List.class);
    - assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMinMax", java.util.Collection.class)).as("$.valueWithMinMax").hasSizeBetween(1, 3);
    + assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMinMax", java.util.Collection.class)).as("$.valueWithMinMax").hasSizeBetween(1, 3);
      assertThat((Object) parsedJson.read("$.valueWithMinEmpty")).isInstanceOf(java.util.List.class);
    - assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMinEmpty", java.util.Collection.class)).as("$.valueWithMinEmpty").hasSizeGreaterThanOrEqualTo(0);
    + assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMinEmpty", java.util.Collection.class)).as("$.valueWithMinEmpty").hasSizeGreaterThanOrEqualTo(0);
      assertThat((Object) parsedJson.read("$.valueWithMaxEmpty")).isInstanceOf(java.util.List.class);
    - assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMaxEmpty", java.util.Collection.class)).as("$.valueWithMaxEmpty").hasSizeLessThanOrEqualTo(0);
    + assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMaxEmpty", java.util.Collection.class)).as("$.valueWithMaxEmpty").hasSizeLessThanOrEqualTo(0);
      assertThatValueIsANumber(parsedJson.read("$.duck"));
      assertThat(parsedJson.read("$.['key'].['complex.key']", String.class)).isEqualTo("foo");
    }]},"response" : { - "status" : 200, - "body" : "{\\"date\\":\\"2017-01-01\\",\\"dateTime\\":\\"2017-01-01T01:23:45\\",\\"aBoolean\\":true,\\"valueWithMax\\":[1,2,3],\\"valueWithOccurrence\\":[1,2,3,4],\\"number\\":123,\\"duck\\":123,\\"alpha\\":\\"abc\\",\\"valueWithMin\\":[1,2,3],\\"time\\":\\"01:02:34\\",\\"valueWithTypeMatch\\":\\"string\\",\\"valueWithMinMax\\":[1,2,3],\\"valueWithoutAMatcher\\":\\"foo\\"}", + "status" : 200, + "body" : "{\\"date\\":\\"2017-01-01\\",\\"dateTime\\":\\"2017-01-01T01:23:45\\",\\"aBoolean\\":true,\\"valueWithMax\\":[1,2,3],\\"valueWithOccurrence\\":[1,2,3,4],\\"number\\":123,\\"duck\\":123,\\"alpha\\":\\"abc\\",\\"valueWithMin\\":[1,2,3],\\"time\\":\\"01:02:34\\",\\"valueWithTypeMatch\\":\\"string\\",\\"valueWithMinMax\\":[1,2,3],\\"valueWithoutAMatcher\\":\\"foo\\"}","headers" : {"Content-Type" : "application/json"}, @@ -1672,7 +1672,7 @@ content type set. Otherwise, the default of application/oc String responseAsString = response.readEntity(String.class); // then: - assertThat(response.getStatus()).isEqualTo(200); + assertThat(response.getStatus()).isEqualTo(200); // and: DocumentContext parsedJson = JsonPath.parse(responseAsString); assertThatJson(parsedJson).field("['property1']").isEqualTo("a"); @@ -1700,9 +1700,9 @@ provide an async() method in the '/get' } response { - status 200 + status 200 body 'Passed' - fixedDelayMilliseconds 1000 + fixedDelayMilliseconds 1000 } }

    YAML.  @@ -1740,12 +1740,12 @@ socket.

    Consider the following contract:

    or
     import org.springframework.boot.web.server.LocalServerPort;
     import org.springframework.boot.test.context.SpringBootTest;
     
    -@SpringBootTest(classes = ContextPathTestingBaseClass.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    +@SpringBootTest(classes = ContextPathTestingBaseClass.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
     class ContextPathTestingBaseClass {
     
    -	@LocalServerPort int port;
    +	@LocalServerPort int port;
     
    -	@Before
    +	@Before
     	public void setup() {
     		RestAssured.baseURI = "http://localhost";
     		RestAssured.port = this.port;
    @@ -1772,10 +1772,10 @@ for WebFlux:

    public abstract class BeerRestBase {
     
    -	@Before
    +	@Before
     	public void setup() {
     		RestAssuredWebTestClient.standaloneSetup(
    -		new ProducerController(personToCheck -> personToCheck.age >= 20));
    +		new ProducerController(personToCheck -> personToCheck.age >= 20));
     	}
     }
     }

    8.9.2 WebFlux with Explicit mode

    Another way is with the EXPLICIT mode in your generated tests @@ -1793,25 +1793,25 @@ to work with WebFlux.

    Maven. 

    contracts {
     		testMode = 'EXPLICIT'
     }

    -

    The following example shows how to set up a base class and Rest Assured for Web Flux:

    @RunWith(SpringRunner.class)
    -@SpringBootTest(classes = BeerRestBase.Config.class,
    +

    The following example shows how to set up a base class and Rest Assured for Web Flux:

    @RunWith(SpringRunner.class)
    +@SpringBootTest(classes = BeerRestBase.Config.class,
     		webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
    -		properties = "server.port=0")
    +		properties = "server.port=0")
     public abstract class BeerRestBase {
     
         // your tests go here
     
         // in this config class you define all controllers and mocked services
    -@Configuration
    -@EnableAutoConfiguration
    +@Configuration
    +@EnableAutoConfiguration
     static class Config {
     
    -	@Bean
    +	@Bean
     	PersonCheckingService personCheckingService()  {
    -		return personToCheck -> personToCheck.age >= 20;
    +		return personToCheck -> personToCheck.age >= 20;
     	}
     
    -	@Bean
    +	@Bean
     	ProducerController producerController() {
     		return new ProducerController(personCheckingService());
     	}
    @@ -1837,18 +1837,18 @@ and the appropriate MatchingType as second. All the
     							}
     							body """
     <test>
    -<duck type='xtype'>123</duck>
    +<duck type='xtype'>123</duck>
     <alpha>abc</alpha>
     <list>
     <elem>abc</elem>
     <elem>def</elem>
     <elem>ghi</elem>
     </list>
    -<number>123</number>
    +<number>123</number>
     <aBoolean>true</aBoolean>
    -<date>2017-01-01</date>
    -<dateTime>2017-01-01T01:23:45</dateTime>
    -<time>01:02:34</time>
    +<date>2017-01-01</date>
    +<dateTime>2017-01-01T01:23:45</dateTime>
    +<time>01:02:34</time>
     <valueWithoutAMatcher>foo</valueWithoutAMatcher>
     <key><complex>foo</complex></key>
     </test>"""
    @@ -1867,7 +1867,7 @@ and the appropriate MatchingType as second. All the
     								xPath('/test/duck/@type', byEquality())
     							}
     						}
    -					}

    And below is an example of a YAML contract with XML request and response bodies:

    include::{verifier_core_path}/src/test/resources/yml/contract_rest_xml.yml

    Here is an example of an automatically generated test for XML response body:

    @Test
    +					}

    And below is an example of a YAML contract with XML request and response bodies:

    include::{verifier_core_path}/src/test/resources/yml/contract_rest_xml.yml

    Here is an example of an automatically generated test for XML response body:

    @Test
     public void validate_xmlMatches() throws Exception {
     	// given:
     	MockMvcRequestSpecification request = given()
    @@ -1877,7 +1877,7 @@ and the appropriate MatchingType as second. All the
     	ResponseOptions response = given().spec(request).get("/get");
     
     	// then:
    -	assertThat(response.statusCode()).isEqualTo(200);
    +	assertThat(response.statusCode()).isEqualTo(200);
     	// and:
     	DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance()
     					.newDocumentBuilder();
    @@ -2078,7 +2078,7 @@ leads to generation of two tests that look more or less like this:

    public class V1Test extends TestBase {
     
    -	@Test
    +	@Test
     	public void validate_should_post_a_user() throws Exception {
     		// given:
     			MockMvcRequestSpecification request = given();
    @@ -2088,11 +2088,11 @@ leads to generation of two tests that look more or less like this:

    "/users/1");
     
     		// then:
    -			assertThat(response.statusCode()).isEqualTo(200);
    +			assertThat(response.statusCode()).isEqualTo(200);
     	}
     
    -	@Test
    -	public void validate_withList_1() throws Exception {
    +	@Test
    +	public void validate_withList_1() throws Exception {
     		// given:
     			MockMvcRequestSpecification request = given();
     
    @@ -2101,7 +2101,7 @@ leads to generation of two tests that look more or less like this:

    "/users/2");
     
     		// then:
    -			assertThat(response.statusCode()).isEqualTo(200);
    +			assertThat(response.statusCode()).isEqualTo(200);
     	}
     
     }

    Notice that, for the contract that has the name field, the generated test method is named @@ -2145,22 +2145,22 @@ testCompile 'org import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; -@RunWith(SpringRunner.class) -@SpringBootTest(classes = Application.class) +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Application.class) public abstract class FraudBaseWithWebAppSetup { private static final String OUTPUT = "target/generated-snippets"; - @Rule + @Rule public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(OUTPUT); - @Rule + @Rule public TestName testName = new TestName(); - @Autowired + @Autowired private WebApplicationContext context; - @Before + @Before public void setup() { RestAssuredMockMvc.mockMvc(MockMvcBuilders.webAppContextSetup(this.context) .apply(documentationConfiguration(this.restDocumentation)) @@ -2190,13 +2190,13 @@ testCompile 'org private static final String OUTPUT = "target/generated-snippets"; - @Rule + @Rule public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(OUTPUT); - @Rule + @Rule public TestName testName = new TestName(); - @Before + @Before public void setup() { RestAssuredMockMvc.standaloneSetup(MockMvcBuilders .standaloneSetup(new FraudDetectionController()) diff --git a/2.1.x/multi/multi_stub-runner-for-messaging.html b/2.1.x/multi/multi_stub-runner-for-messaging.html index b0e8bbb4dc..4ef2ba5f61 100644 --- a/2.1.x/multi/multi_stub-runner-for-messaging.html +++ b/2.1.x/multi/multi_stub-runner-for-messaging.html @@ -9,14 +9,14 @@ That way the only remaining framework is Spring AMQP.

    [Important]Important

    Notice that, for the byCommand method, the example calls the assertThatValueIsANumber. This method must be defined in the test base class or be @@ -1604,8 +1604,8 @@ the method name and passed the proper JSON path as a parameter to it.

    import java.util.Collection; import java.util.Map; -/** +/** * Contract for triggering stub messages. * * @author Marcin Grzejszczak - */ + */ public interface StubTrigger { - /** + /** * Triggers an event by a given label for a given {@code groupid:artifactid} notation. * You can use only {@code artifactId} too. * @@ -24,30 +24,30 @@ That way the only remaining framework is Spring AMQP.

    + */ boolean trigger(String ivyNotation, String labelName); - /** + /** * Triggers an event by a given label. * * Feature related to messaging. * @param labelName name of the label to trigger * @return true - if managed to run a trigger - */ + */ boolean trigger(String labelName); - /** + /** * Triggers all possible events. * * Feature related to messaging. * @return true - if managed to run a trigger - */ + */ boolean trigger(); - /** + /** * Feature related to messaging. * @return a mapping of ivy notation of a dependency to all the labels it has. - */ + */ Map<String, Collection<String>> labels(); }

    For convenience, the StubFinder interface extends StubTrigger, so you only need one @@ -62,9 +62,9 @@ Remember to annotate your test class with @AutoConfigureSt └── accurest └── stubs └── camelService - ├── 0.0.1-SNAPSHOT - │   ├── camelService-0.0.1-SNAPSHOT.pom - │   ├── camelService-0.0.1-SNAPSHOT-stubs.jar + ├── 0.0.1-SNAPSHOT + │   ├── camelService-0.0.1-SNAPSHOT.pom + │   ├── camelService-0.0.1-SNAPSHOT-stubs.jar │   └── maven-metadata-local.xml └── maven-metadata-local.xml

    And the stubs contain the following structure:

    ├── META-INF
     │   └── MANIFEST.MF
    @@ -105,10 +105,10 @@ Remember to annotate your test class with @AutoConfigureSt
     			header('BOOK-NAME', 'foo')
     		}
     	}
    -}

Scenario 1 (no input message)

So as to trigger a message via the return_book_1 label we’ll use the StubTigger interface as follows

stubFinder.trigger('return_book_1')

Next we’ll want to listen to the output of the message sent to jms:output

Exchange receivedMessage = consumerTemplate.receive('jms:output', 5000)

And the received message would pass the following assertions

receivedMessage != null
+}

Scenario 1 (no input message)

So as to trigger a message via the return_book_1 label we’ll use the StubTigger interface as follows

stubFinder.trigger('return_book_1')

Next we’ll want to listen to the output of the message sent to jms:output

Exchange receivedMessage = consumerTemplate.receive('jms:output', 5000)

And the received message would pass the following assertions

receivedMessage != null
 assertThatBodyContainsBookNameFoo(receivedMessage.in.body)
 receivedMessage.in.headers.get('BOOK-NAME') == 'foo'

Scenario 2 (output triggered by input)

Since the route is set for you it’s enough to just send a message to the jms:output destination.

producerTemplate.
-		sendBodyAndHeaders('jms:input', new BookReturned('foo'), [sample: 'header'])

Next we’ll want to listen to the output of the message sent to jms:output

Exchange receivedMessage = consumerTemplate.receive('jms:output', 5000)

And the received message would pass the following assertions

receivedMessage != null
+		sendBodyAndHeaders('jms:input', new BookReturned('foo'), [sample: 'header'])

Next we’ll want to listen to the output of the message sent to jms:output

Exchange receivedMessage = consumerTemplate.receive('jms:output', 5000)

And the received message would pass the following assertions

receivedMessage != null
 assertThatBodyContainsBookNameFoo(receivedMessage.in.body)
 receivedMessage.in.headers.get('BOOK-NAME') == 'foo'

Scenario 3 (input with no output)

Since the route is set for you it’s enough to just send a message to the jms:output destination.

producerTemplate.
 		sendBodyAndHeaders('jms:delete', new BookReturned('foo'), [sample: 'header'])

7.3 Stub Runner Integration

Spring Cloud Contract Verifier Stub Runner’s messaging module gives you an easy way to @@ -123,9 +123,9 @@ classpath. Remember to annotate your test class with @Auto └── accurest └── stubs └── integrationService - ├── 0.0.1-SNAPSHOT - │   ├── integrationService-0.0.1-SNAPSHOT.pom - │   ├── integrationService-0.0.1-SNAPSHOT-stubs.jar + ├── 0.0.1-SNAPSHOT + │   ├── integrationService-0.0.1-SNAPSHOT.pom + │   ├── integrationService-0.0.1-SNAPSHOT-stubs.jar │   └── maven-metadata-local.xml └── maven-metadata-local.xml

Further assume the stubs contain the following structure:

├── META-INF
 │   └── MANIFEST.MF
@@ -166,7 +166,7 @@ classpath. Remember to annotate your test class with @Auto
 			header('BOOK-NAME', 'foo')
 		}
 	}
-}

and the following Spring Integration Route:

<?xml version="1.0" encoding="UTF-8"?>
+}

and the following Spring Integration Route:

<?xml version="1.0" encoding="UTF-8"?>
 <beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 			 xmlns:beans="http://www.springframework.org/schema/beans"
 			 xmlns="http://www.springframework.org/schema/integration"
@@ -213,9 +213,9 @@ property.

Assume that you have the following Maven repository with a deplo └── accurest └── stubs └── streamService - ├── 0.0.1-SNAPSHOT - │   ├── streamService-0.0.1-SNAPSHOT.pom - │   ├── streamService-0.0.1-SNAPSHOT-stubs.jar + ├── 0.0.1-SNAPSHOT + │   ├── streamService-0.0.1-SNAPSHOT.pom + │   ├── streamService-0.0.1-SNAPSHOT-stubs.jar │   └── maven-metadata-local.xml └── maven-metadata-local.xml

Further assume the stubs contain the following structure:

├── META-INF
 │   └── MANIFEST.MF
@@ -249,7 +249,7 @@ property.

Assume that you have the following Maven repository with a deplo headers { header('BOOK-NAME', 'foo') } } }

Now consider the following Spring configuration:

stubrunner.repositoryRoot: classpath:m2repo/repository/
-stubrunner.ids: org.springframework.cloud.contract.verifier.stubs:streamService:0.0.1-SNAPSHOT:stubs
+stubrunner.ids: org.springframework.cloud.contract.verifier.stubs:streamService:0.0.1-SNAPSHOT:stubs
 stubrunner.stubs-mode: remote
 spring:
   cloud:
@@ -261,7 +261,7 @@ property.

Assume that you have the following Maven repository with a deplo destination: bookStorage server: - port: 0 + port: 0 debug: true

These examples lend themselves to three scenarios:

Scenario 1 (no input message)

To trigger a message via the return_book_1 label, use the StubTrigger interface as follows:

stubFinder.trigger('return_book_1')

To listen to the output of the message sent to a channel whose destination is @@ -294,9 +294,9 @@ to disable them explicitly by setting the stubrunner.stre └── com └── example └── spring-cloud-contract-amqp-test - ├── 0.4.0-SNAPSHOT - │   ├── spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT.pom - │   ├── spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT-stubs.jar + ├── 0.4.0-SNAPSHOT + │   ├── spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT.pom + │   ├── spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT-stubs.jar │   └── maven-metadata-local.xml └── maven-metadata-local.xml

Further assume that the stubs contain the following structure:

├── META-INF
 │   └── MANIFEST.MF
@@ -321,25 +321,25 @@ to disable them explicitly by setting the  stubrunner.stre
 		}
 		// the body of the output message
 		body([
-				id  : $(consumer(9), producer(regex("[0-9]+"))),
+				id  : $(consumer(9), producer(regex("[0-9]+"))),
 				name: "me"
 		])
 	}
 }

Now consider the following Spring configuration:

stubrunner:
   repositoryRoot: classpath:m2repo/repository/
-  ids: org.springframework.cloud.contract.verifier.stubs.amqp:spring-cloud-contract-amqp-test:0.4.0-SNAPSHOT:stubs
+  ids: org.springframework.cloud.contract.verifier.stubs.amqp:spring-cloud-contract-amqp-test:0.4.0-SNAPSHOT:stubs
   stubs-mode: remote
   amqp:
     enabled: true
 server:
-  port: 0

Triggering the message

To trigger a message using the contract above, use the StubTrigger interface as + port: 0

Triggering the message

To trigger a message using the contract above, use the StubTrigger interface as follows:

stubTrigger.trigger("contract-test.person.created.event")

The message has a destination of contract-test.exchange, so the Spring AMQP stub runner -integration looks for bindings related to this exchange.

@Bean
+integration looks for bindings related to this exchange.

@Bean
 public Binding binding() {
 	return BindingBuilder.bind(new Queue("test.queue"))
 			.to(new DirectExchange("contract-test.exchange")).with("#");
 }

The binding definition binds the queue test.queue. As a result, the following listener -definition is matched and invoked with the contract message.

@Bean
+definition is matched and invoked with the contract message.

@Bean
 public SimpleMessageListenerContainer simpleMessageListenerContainer(
 		ConnectionFactory connectionFactory,
 		MessageListenerAdapter listenerAdapter) {
@@ -349,7 +349,7 @@ definition is matched and invoked with the contract message.

return container;
-}

Also, the following annotated listener matches and is invoked:

@RabbitListener(bindings = @QueueBinding(value = @Queue("test.queue"), exchange = @Exchange(value = "contract-test.exchange", ignoreDeclarationExceptions = "true")))
+}

Also, the following annotated listener matches and is invoked:

@RabbitListener(bindings = @QueueBinding(value = @Queue("test.queue"), exchange = @Exchange(value = "contract-test.exchange", ignoreDeclarationExceptions = "true")))
 public void handlePerson(Person person) {
 	this.person = person;
 }
[Note]Note

The message is directly handed over to the onMessage method of the diff --git a/2.1.x/single/spring-cloud-contract.html b/2.1.x/single/spring-cloud-contract.html index aadfc7f824..eb43a3e2f4 100644 --- a/2.1.x/single/spring-cloud-contract.html +++ b/2.1.x/single/spring-cloud-contract.html @@ -70,10 +70,10 @@ Stub Runner properties, as shown in the following example:

  ids: 'com.example:http-server-dsl:+:stubs:8080'
   repositoryRoot: https://repo.spring.io/libs-snapshot

Now you can annotate your test class with @AutoConfigureStubRunner. In the annotation, provide the group-id and artifact-id values for Spring Cloud Contract Stub Runner to -run the collaborators' stubs for you, as shown in the following example:

@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment=WebEnvironment.NONE)
-@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
-		stubsMode = StubRunnerProperties.StubsMode.LOCAL)
+run the collaborators' stubs for you, as shown in the following example:

@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment=WebEnvironment.NONE)
+@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
+		stubsMode = StubRunnerProperties.StubsMode.LOCAL)
 public class LoanApplicationServiceTests {
[Tip]Tip

Use the REMOTE stubsMode when downloading stubs from an online repository and LOCAL for offline work.

Now, in your integration test, you can receive stubbed versions of HTTP responses or messages that are expected to be emitted by the collaborator service.

2.4.2 A Three-minute Tour

This brief tour walks through using Spring Cloud Contract:

You can find an even more brief tour @@ -89,7 +89,7 @@ org.springframework.cloud.contract.spec.Contract.make { url '/fraudcheck' body([ "client.id": $(regex('[0-9]{10}')), - loanAmount: 99999 + loanAmount: 99999 ]) headers { contentType('application/json') @@ -109,8 +109,8 @@ org.springframework.cloud.contract.spec.Contract.make { method: PUT url: /fraudcheck body: - "client.id": 1234567890 - loanAmount: 99999 + "client.id": 1234567890 + loanAmount: 99999 headers: Content-Type: application/json matchers: @@ -119,12 +119,12 @@ org.springframework.cloud.contract.spec.Contract.make { type: by_regex value: "[0-9]{10}" response: - status: 200 + status: 200 body: fraudCheckStatus: "FRAUD" "rejection.reason": "Amount too high" headers: - Content-Type: application/json;charset=UTF-8

In the case of messaging, you can define:

  • The input and the output messages can be defined (taking into account from and where it + Content-Type: application/json;charset=UTF-8

    In the case of messaging, you can define:

    • The input and the output messages can be defined (taking into account from and where it was sent, the message body, and the header).
    • The methods that should be called after the message is received.
    • The methods that, when called, should trigger a message.

    The following example shows a Camel messaging contract expressed in Groovy DSL:

    			def contractDsl = Contract.make {
     				label 'some_label'
     				input {
    @@ -157,7 +157,7 @@ portion of the file:

    <extensions>true</extensions>
     </plugin>

    Running ./mvnw clean install automatically generates tests that verify the application compliance with the added contracts. By default, the generated tests are under -org.springframework.cloud.contract.verifier.tests..

    The following example shows a sample auto-generated test for an HTTP contract:

    @Test
    +org.springframework.cloud.contract.verifier.tests..

    The following example shows a sample auto-generated test for an HTTP contract:

    @Test
     public void validate_shouldMarkClientAsFraud() throws Exception {
         // given:
             MockMvcRequestSpecification request = given()
    @@ -169,7 +169,7 @@ compliance with the added contracts. By default, the generated tests are under
                     .put("/fraudcheck");
     
         // then:
    -        assertThat(response.statusCode()).isEqualTo(200);
    +        assertThat(response.statusCode()).isEqualTo(200);
             assertThat(response.header("Content-Type")).matches("application/vnd.fraud.v1.json.*");
         // and:
             DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
    @@ -218,18 +218,18 @@ contain all the setup necessary to run them (for example, 
     setup or messaging test setup).

    Once the implementation and the test base class are in place, the tests pass, and both the application and the stub artifacts are built and installed in the local Maven repository. Information about installing the stubs jar to the local repository appears in the logs, as -shown in the following example:

    [INFO] --- spring-cloud-contract-maven-plugin:1.0.0.BUILD-SNAPSHOT:generateStubs (default-generateStubs) @ http-server ---
    -[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar
    +shown in the following example:

    [INFO] --- spring-cloud-contract-maven-plugin:1.0.0.BUILD-SNAPSHOT:generateStubs (default-generateStubs) @ http-server ---
    +[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar
     [INFO]
    -[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ http-server ---
    -[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar
    +[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ http-server ---
    +[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar
     [INFO]
    -[INFO] --- spring-boot-maven-plugin:1.5.5.BUILD-SNAPSHOT:repackage (default) @ http-server ---
    +[INFO] --- spring-boot-maven-plugin:1.5.5.BUILD-SNAPSHOT:repackage (default) @ http-server ---
     [INFO]
    -[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ http-server ---
    -[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.jar
    -[INFO] Installing /some/path/http-server/pom.xml to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.pom
    -[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar

    You can now merge the changes and publish both the application and the stub artifacts +[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ http-server --- +[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.jar +[INFO] Installing /some/path/http-server/pom.xml to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.pom +[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar

    You can now merge the changes and publish both the application and the stub artifacts in an online repository.

    Docker Project

    In order to enable working with contracts while creating applications in non-JVM technologies, the springcloud/spring-cloud-contract Docker image has been created. It contains a project that automatically generates tests for HTTP contracts and executes them @@ -250,20 +250,20 @@ Runner properties, as shown in the following example:

      ids: 'com.example:http-server-dsl:+:stubs:8080'
       repositoryRoot: https://repo.spring.io/libs-snapshot

Now you can annotate your test class with @AutoConfigureStubRunner. In the annotation, provide the group-id and artifact-id for Spring Cloud Contract Stub Runner to run -the collaborators' stubs for you, as shown in the following example:

@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment=WebEnvironment.NONE)
-@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
-		stubsMode = StubRunnerProperties.StubsMode.LOCAL)
+the collaborators' stubs for you, as shown in the following example:

@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment=WebEnvironment.NONE)
+@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
+		stubsMode = StubRunnerProperties.StubsMode.LOCAL)
 public class LoanApplicationServiceTests {
[Tip]Tip

Use the REMOTE stubsMode when downloading stubs from an online repository and LOCAL for offline work.

In your integration test, you can receive stubbed versions of HTTP responses or messages that are expected to be emitted by the collaborator service. You can see entries similar -to the following in the build logs:

2016-07-19 14:22:25.403  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Desired version is + - will try to resolve the latest version
-2016-07-19 14:22:25.438  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved version is 0.0.1-SNAPSHOT
-2016-07-19 14:22:25.439  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolving artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT using remote repositories []
-2016-07-19 14:22:25.451  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar
-2016-07-19 14:22:25.465  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacking stub from JAR [URI: file:/path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar]
-2016-07-19 14:22:25.475  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacked file to [/var/folders/0p/xwq47sq106x1_g3dtv6qfm940000gq/T/contracts100276532569594265]
-2016-07-19 14:22:27.737  INFO 41050 --- [           main] o.s.c.c.stubrunner.StubRunnerExecutor    : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server:0.0.1-SNAPSHOT:stubs=8080}]

2.4.3 Defining the Contract

As consumers of services, we need to define what exactly we want to achieve. We need to +to the following in the build logs:

2016-07-19 14:22:25.403  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Desired version is + - will try to resolve the latest version
+2016-07-19 14:22:25.438  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved version is 0.0.1-SNAPSHOT
+2016-07-19 14:22:25.439  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolving artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT using remote repositories []
+2016-07-19 14:22:25.451  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar
+2016-07-19 14:22:25.465  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacking stub from JAR [URI: file:/path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar]
+2016-07-19 14:22:25.475  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacked file to [/var/folders/0p/xwq47sq106x1_g3dtv6qfm940000gq/T/contracts100276532569594265]
+2016-07-19 14:22:27.737  INFO 41050 --- [           main] o.s.c.c.stubrunner.StubRunnerExecutor    : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server:0.0.1-SNAPSHOT:stubs=8080}]

2.4.3 Defining the Contract

As consumers of services, we need to define what exactly we want to achieve. We need to formulate our expectations. That is why we write contracts.

Assume that you want to send a request containing the ID of a client company and the amount it wants to borrow from us. You also want to send it to the /fraudcheck url via the PUT method.

Groovy DSL.  @@ -291,7 +291,7 @@ org.springframework.cloud.contract.spec.Contract.make { url '/fraudcheck' // (3) body([ // (4) "client.id": $(regex('[0-9]{10}')), - loanAmount : 99999 + loanAmount : 99999 ]) headers { // (5) contentType('application/json') @@ -397,16 +397,16 @@ response: # (7) You get a running WireMock instance/Messaging route that simulates the service. You would like to feed that instance with a proper stub definition.

At some point in time, you need to send a request to the Fraud Detection service.

ResponseEntity<FraudServiceResponse> response = restTemplate.exchange(
 		"http://localhost:" + port + "/fraudcheck", HttpMethod.PUT,
-		new HttpEntity<>(request, httpHeaders), FraudServiceResponse.class);

Annotate your test class with @AutoConfigureStubRunner. In the annotation provide the group id and artifact id for the Stub Runner to download stubs of your collaborators.

@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment = WebEnvironment.NONE)
-@AutoConfigureStubRunner(ids = {
-		"com.example:http-server-dsl:+:stubs:6565" }, stubsMode = StubRunnerProperties.StubsMode.LOCAL)
+		new HttpEntity<>(request, httpHeaders), FraudServiceResponse.class);

Annotate your test class with @AutoConfigureStubRunner. In the annotation provide the group id and artifact id for the Stub Runner to download stubs of your collaborators.

@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.NONE)
+@AutoConfigureStubRunner(ids = {
+		"com.example:http-server-dsl:+:stubs:6565" }, stubsMode = StubRunnerProperties.StubsMode.LOCAL)
 public class LoanApplicationServiceTests {

After that, during the tests, Spring Cloud Contract automatically finds the stubs (simulating the real service) in the Maven repository and exposes them on a configured (or random) port.

2.4.5 Server Side

Since you are developing your stub, you need to be sure that it actually resembles your concrete implementation. You cannot have a situation where your stub acts in one way and your application behaves in a different way, especially in production.

To ensure that your application behaves the way you define in your stub, tests are -generated from the stub you provide.

The autogenerated test looks, more or less, like this:

@Test
+generated from the stub you provide.

The autogenerated test looks, more or less, like this:

@Test
 public void validate_shouldMarkClientAsFraud() throws Exception {
     // given:
         MockMvcRequestSpecification request = given()
@@ -418,7 +418,7 @@ generated from the stub you provide.

The autogenerated test looks, more or .put("/fraudcheck"); // then: - assertThat(response.statusCode()).isEqualTo(200); + assertThat(response.statusCode()).isEqualTo(200); assertThat(response.header("Content-Type")).matches("application/vnd.fraud.v1.json.*"); // and: DocumentContext parsedJson = JsonPath.parse(response.getBody().asString()); @@ -495,11 +495,11 @@ following section to your build:

Maven.  maven { url "https://repo.spring.io/milestone" } maven { url "https://repo.spring.io/release" } }

-

2.5.2 Consumer side (Loan Issuance)

As a developer of the Loan Issuance service (a consumer of the Fraud Detection server), you might do the following steps:

  1. Start doing TDD by writing a test for your feature.
  2. Write the missing implementation.
  3. Clone the Fraud Detection service repository locally.
  4. Define the contract locally in the repo of Fraud Detection service.
  5. Add the Spring Cloud Contract Verifier plugin.
  6. Run the integration tests.
  7. File a pull request.
  8. Create an initial implementation.
  9. Take over the pull request.
  10. Write the missing implementation.
  11. Deploy your app.
  12. Work online.

Start doing TDD by writing a test for your feature.

@Test
+

2.5.2 Consumer side (Loan Issuance)

As a developer of the Loan Issuance service (a consumer of the Fraud Detection server), you might do the following steps:

  1. Start doing TDD by writing a test for your feature.
  2. Write the missing implementation.
  3. Clone the Fraud Detection service repository locally.
  4. Define the contract locally in the repo of Fraud Detection service.
  5. Add the Spring Cloud Contract Verifier plugin.
  6. Run the integration tests.
  7. File a pull request.
  8. Create an initial implementation.
  9. Take over the pull request.
  10. Write the missing implementation.
  11. Deploy your app.
  12. Work online.

Start doing TDD by writing a test for your feature.

@Test
 public void shouldBeRejectedDueToAbnormalLoanAmount() {
 	// given:
 	LoanApplication application = new LoanApplication(new Client("1234567890"),
-			99999);
+			99999);
 	// when:
 	LoanApplicationResult loanApplication = service.loanApplication(application);
 	// then:
@@ -541,7 +541,7 @@ org.springframework.cloud.contract.spec.Contract.make {
 		url '/fraudcheck' // (3)
 		body([ // (4)
 			   "client.id": $(regex('[0-9]{10}')),
-			   loanAmount : 99999
+			   loanAmount : 99999
 		])
 		headers { // (5)
 			contentType('application/json')
@@ -678,18 +678,18 @@ First, add the Spring Cloud Contract BOM.

</plugin>

Since the plugin was added, you get the Spring Cloud Contract Verifier features which, from the provided contracts:

  • generate and run tests
  • produce and install stubs

You do not want to generate tests since you, as the consumer, want only to play with the stubs. You need to skip the test generation and execution. When you execute:

$ cd local-http-server-repo
-$ ./mvnw clean install -DskipTests

In the logs, you see something like this:

[INFO] --- spring-cloud-contract-maven-plugin:1.0.0.BUILD-SNAPSHOT:generateStubs (default-generateStubs) @ http-server ---
-[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar
+$ ./mvnw clean install -DskipTests

In the logs, you see something like this:

[INFO] --- spring-cloud-contract-maven-plugin:1.0.0.BUILD-SNAPSHOT:generateStubs (default-generateStubs) @ http-server ---
+[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar
 [INFO]
-[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ http-server ---
-[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar
+[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ http-server ---
+[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar
 [INFO]
-[INFO] --- spring-boot-maven-plugin:1.5.5.BUILD-SNAPSHOT:repackage (default) @ http-server ---
+[INFO] --- spring-boot-maven-plugin:1.5.5.BUILD-SNAPSHOT:repackage (default) @ http-server ---
 [INFO]
-[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ http-server ---
-[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.jar
-[INFO] Installing /some/path/http-server/pom.xml to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.pom
-[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar

The following line is extremely important:

[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar

It confirms that the stubs of the http-server have been installed in the local +[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ http-server --- +[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.jar +[INFO] Installing /some/path/http-server/pom.xml to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.pom +[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar

The following line is extremely important:

[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar

It confirms that the stubs of the http-server have been installed in the local repository.

Run the integration tests.

In order to profit from the Spring Cloud Contract Stub Runner functionality of automatic stub downloading, you must do the following in your consumer side project (Loan Application service):

Add the Spring Cloud Contract BOM:

<dependencyManagement>
@@ -709,23 +709,23 @@ Application service):

Add the Spring Cloud Co </dependency>

Annotate your test class with @AutoConfigureStubRunner. In the annotation, provide the group-id and artifact-id for the Stub Runner to download the stubs of your collaborators. (Optional step) Because you’re playing with the collaborators offline, you -can also provide the offline work switch (StubRunnerProperties.StubsMode.LOCAL).

@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment = WebEnvironment.NONE)
-@AutoConfigureStubRunner(ids = {
-		"com.example:http-server-dsl:+:stubs:6565" }, stubsMode = StubRunnerProperties.StubsMode.LOCAL)
-public class LoanApplicationServiceTests {

Now, when you run your tests, you see something like this:

2016-07-19 14:22:25.403  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Desired version is + - will try to resolve the latest version
-2016-07-19 14:22:25.438  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved version is 0.0.1-SNAPSHOT
-2016-07-19 14:22:25.439  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolving artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT using remote repositories []
-2016-07-19 14:22:25.451  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar
-2016-07-19 14:22:25.465  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacking stub from JAR [URI: file:/path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar]
-2016-07-19 14:22:25.475  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacked file to [/var/folders/0p/xwq47sq106x1_g3dtv6qfm940000gq/T/contracts100276532569594265]
-2016-07-19 14:22:27.737  INFO 41050 --- [           main] o.s.c.c.stubrunner.StubRunnerExecutor    : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server:0.0.1-SNAPSHOT:stubs=8080}]

This output means that Stub Runner has found your stubs and started a server for your app +can also provide the offline work switch (StubRunnerProperties.StubsMode.LOCAL).

@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.NONE)
+@AutoConfigureStubRunner(ids = {
+		"com.example:http-server-dsl:+:stubs:6565" }, stubsMode = StubRunnerProperties.StubsMode.LOCAL)
+public class LoanApplicationServiceTests {

Now, when you run your tests, you see something like this:

2016-07-19 14:22:25.403  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Desired version is + - will try to resolve the latest version
+2016-07-19 14:22:25.438  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved version is 0.0.1-SNAPSHOT
+2016-07-19 14:22:25.439  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolving artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT using remote repositories []
+2016-07-19 14:22:25.451  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar
+2016-07-19 14:22:25.465  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacking stub from JAR [URI: file:/path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar]
+2016-07-19 14:22:25.475  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacked file to [/var/folders/0p/xwq47sq106x1_g3dtv6qfm940000gq/T/contracts100276532569594265]
+2016-07-19 14:22:27.737  INFO 41050 --- [           main] o.s.c.c.stubrunner.StubRunnerExecutor    : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server:0.0.1-SNAPSHOT:stubs=8080}]

This output means that Stub Runner has found your stubs and started a server for your app with group id com.example, artifact id http-server with version 0.0.1-SNAPSHOT of the stubs and with stubs classifier on port 8080.

File a pull request.

What you have done until now is an iterative process. You can play around with the contract, install it locally, and work on the consumer side until the contract works as you wish.

Once you are satisfied with the results and the test passes, publish a pull request to -the server side. Currently, the consumer side work is done.

2.5.3 Producer side (Fraud Detection server)

As a developer of the Fraud Detection server (a server to the Loan Issuance service):

Create an initial implementation.

As a reminder, you can see the initial implementation here:

@RequestMapping(value = "/fraudcheck", method = PUT)
-public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) {
+the server side. Currently, the consumer side work is done.

2.5.3 Producer side (Fraud Detection server)

As a developer of the Fraud Detection server (a server to the Loan Issuance service):

Create an initial implementation.

As a reminder, you can see the initial implementation here:

@RequestMapping(value = "/fraudcheck", method = PUT)
+public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) {
 return new FraudCheckResult(FraudCheckStatus.OK, NO_REASON);
 }

Take over the pull request.

$ git checkout -b contract-change-pr master
 $ git pull https://your-git-server.com/server-side-fork.git contract-change-pr

You must add the dependencies needed by the autogenerated tests:

<dependency>
@@ -771,7 +771,7 @@ start the server side FraudDetectionController.

public class FraudBase { - @Before + @Before public void setup() { RestAssuredMockMvc.standaloneSetup(new FraudDetectionController(), new FraudStatsController(stubbedStatsProvider())); @@ -781,11 +781,11 @@ start the server side FraudDetectionController.

return fraudType -> { switch (fraudType) { case DRUNKS: - return 100; + return 100; case ALL: - return 200; + return 200; } - return 0; + return 0; }; } @@ -796,9 +796,9 @@ start the server side FraudDetectionController.

}

Now, if you run the ./mvnw clean install, you get something like this:

Results :
 
 Tests in error:
-  ContractVerifierTest.validate_shouldMarkClientAsFraud:32 » IllegalState Parsed...

This error occurs because you have a new contract from which a test was generated and it + ContractVerifierTest.validate_shouldMarkClientAsFraud:32 » IllegalState Parsed...

This error occurs because you have a new contract from which a test was generated and it failed since you have not implemented the feature. The auto-generated test would look -like this:

@Test
+like this:

@Test
 public void validate_shouldMarkClientAsFraud() throws Exception {
     // given:
         MockMvcRequestSpecification request = given()
@@ -810,7 +810,7 @@ like this:

"/fraudcheck");
 
     // then:
-        assertThat(response.statusCode()).isEqualTo(200);
+        assertThat(response.statusCode()).isEqualTo(200);
         assertThat(response.header("Content-Type")).matches("application/vnd.fraud.v1.json.*");
     // and:
         DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
@@ -823,8 +823,8 @@ in the form of a test. This test sends a request to our own application with the
 headers, and body defined in the contract. It also is expecting precisely defined values
 in the response. In other words, you have the red part of red, green, and
 refactor. It is time to convert the red into the green.

Write the missing implementation.

Because you know the expected input and expected output, you can write the missing -implementation:

@RequestMapping(value = "/fraudcheck", method = PUT)
-public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) {
+implementation:

@RequestMapping(value = "/fraudcheck", method = PUT)
+public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) {
 if (amountGreaterThanThreshold(fraudCheck)) {
 	return new FraudCheckResult(FraudCheckStatus.FRAUD, AMOUNT_TOO_HIGH);
 }
@@ -918,7 +918,7 @@ different approaches.

    Let’s assume that you do version your API. In that case you should provide as many contracts as many versions you support. You can create a subfolder for every version or append it to the contract name - whatever suits you more.

3.4.2 JAR versioning

If by versioning you mean the version of the JAR that contains the stubs then there are essentially two main approaches.

Let’s assume that you’re doing Continuous Delivery / Deployment which means that you’re generating a new version of the jar each time you go through the pipeline and that jar can go to production at any time. For example your jar version -looks like this (it got built on the 20.10.2016 at 20:15:21) :

1.0.0.20161020-201521-RELEASE

In that case your generated stub jar will look like this.

1.0.0.20161020-201521-RELEASE-stubs.jar

In this case you should inside your application.yml or @AutoConfigureStubRunner when referencing stubs provide the +looks like this (it got built on the 20.10.2016 at 20:15:21) :

1.0.0.20161020-201521-RELEASE

In that case your generated stub jar will look like this.

1.0.0.20161020-201521-RELEASE-stubs.jar

In this case you should inside your application.yml or @AutoConfigureStubRunner when referencing stubs provide the latest version of the stubs. You can do that by passing the + sign. Example

@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:8080"})

If the versioning however is fixed (e.g. 1.0.4.RELEASE or 2.1.1) then you have to set the concrete value of the jar version. Example for 2.1.1.

@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:2.1.1:stubs:8080"})

3.4.3 Dev or prod stubs

You can manipulate the classifier to run the tests against current development version of the stubs of other services or the ones that were deployed to production. If you alter your build to deploy the stubs with the prod-stubs classifier @@ -945,7 +945,7 @@ consumer you will break with your local changes.

As you can see under the slash-delimited groupid / artifact id folder (com/example/server) you have expectations of the 3 consumers (client1, client2 and client3). Expectations are the standard Groovy DSL contract files as described throughout this documentation. This repository has to produce a JAR file that maps -one to one to the contents of the repo.

Example of a pom.xml inside the server folder.

<?xml version="1.0" encoding="UTF-8"?>
+one to one to the contents of the repo.

Example of a pom.xml inside the server folder.

<?xml version="1.0" encoding="UTF-8"?>
 <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 		 xmlns="http://maven.apache.org/POM/4.0.0"
 		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
@@ -1056,7 +1056,7 @@ one to one to the contents of the repo.

Example of a </project>

As you can see there are no dependencies other than the Spring Cloud Contract Maven Plugin. Those poms are necessary for the consumer side to run mvn clean install -DskipTests to locally install - stubs of the producer project.

The pom.xml in the root folder can look like this:

<?xml version="1.0" encoding="UTF-8"?>
+ stubs of the producer project.

The pom.xml in the root folder can look like this:

<?xml version="1.0" encoding="UTF-8"?>
 <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 		 xmlns="http://maven.apache.org/POM/4.0.0"
 		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
@@ -1527,14 +1527,14 @@ dependencies {
     testCompile("org.springframework.cloud:spring-cloud-contract-pact")
 }

Next, just pass the URL of the Pact Broker to repositoryRoot, prefixed -with pact:// protocol. E.g. pact://http://localhost:8085

@RunWith(SpringRunner.class)
-@SpringBootTest
-@AutoConfigureStubRunner(stubsMode = StubRunnerProperties.StubsMode.REMOTE,
+with pact:// protocol. E.g. pact://http://localhost:8085

@RunWith(SpringRunner.class)
+@SpringBootTest
+@AutoConfigureStubRunner(stubsMode = StubRunnerProperties.StubsMode.REMOTE,
 		ids = "com.example:beer-api-producer-pact",
-		repositoryRoot = "pact://http://localhost:8085")
+		repositoryRoot = "pact://http://localhost:8085")
 public class BeerControllerTest {
     //Inject the port of the running stub
-    @StubRunnerPort("beer-api-producer-pact") int producerPort;
+    @StubRunnerPort("beer-api-producer-pact") int producerPort;
     //...
 }

With such a setup:

  • Pact files will be downloaded from the Pact Broker
  • Spring Cloud Contract will convert the Pact files into stub definitions
  • The stub servers will be started and fed with stubs

For more information about Pact support you can go to the Section 10.7, “Using the Pact Stub Downloader” section.

3.8 How can I debug the request/response being sent by the generated tests client?

The generated tests all boil down to RestAssured in some form or fashion which relies on Apache HttpClient. HttpClient has a facility called wire logging which logs the entire request and response to HttpClient. Spring Boot has a logging common application property for doing this sort of thing, just add this to your application properties

logging.level.org.apache.http.wire=DEBUG

3.8.1 How can I debug the mapping/request/response being sent by WireMock?

Starting from version 1.2.0 we turn on WireMock logging to @@ -1697,7 +1697,7 @@ endpoint, which should be verified.

void isProperCorrelationId(Integer correlationId) {
-		assert correlationId == 123456
+		assert correlationId == 123456
 	}
 
 	void isEmpty(String value) {
@@ -1736,20 +1736,20 @@ via contractsProperties method e.g. 

4.1.14 Spring Cloud Contract Verifier on the Consumer Side

In a consuming service, you need to configure the Spring Cloud Contract Verifier plugin in exactly the same way as in case of provider. If you do not want to use Stub Runner then you need to copy contracts stored in src/test/resources/contracts and generate -WireMock JSON stubs using:

./gradlew generateClientStubs
[Note]Note

The stubsOutputDir option has to be set for stub generation to work.

When present, JSON stubs can be used in automated tests of consuming a service.

@ContextConfiguration(loader == SpringApplicationContextLoader, classes == Application)
+WireMock JSON stubs using:

./gradlew generateClientStubs
[Note]Note

The stubsOutputDir option has to be set for stub generation to work.

When present, JSON stubs can be used in automated tests of consuming a service.

@ContextConfiguration(loader == SpringApplicationContextLoader, classes == Application)
 class LoanApplicationServiceSpec extends Specification {
 
- @ClassRule
- @Shared
+ @ClassRule
+ @Shared
  WireMockClassRule wireMockRule == new WireMockClassRule()
 
- @Autowired
+ @Autowired
  LoanApplicationService sut
 
  def 'should successfully apply for loan'() {
    given:
  	LoanApplication application =
-			new LoanApplication(client: new Client(clientPesel: '12345678901'), amount: 123.123)
+			new LoanApplication(client: new Client(clientPesel: '12345678901'), amount: 123.123)
    when:
 	LoanApplicationResult loanApplication == sut.loanApplication(application)
    then:
@@ -1797,13 +1797,13 @@ Assured 2.x by adding it to the plugins classpath, as shown here:

2.5.0</version>
+           <version>2.5.0</version>
            <scope>compile</scope>
         </dependency>
         <dependency>
            <groupId>com.jayway.restassured</groupId>
            <artifactId>spring-mock-mvc</artifactId>
-           <version>2.5.0</version>
+           <version>2.5.0</version>
            <scope>compile</scope>
         </dependency>
     </dependencies>
@@ -1815,13 +1815,13 @@ Assured 2.x by adding it to the plugins classpath, as shown here:

2.5.0</version>
+       <version>2.5.0</version>
        <scope>test</scope>
     </dependency>
     <dependency>
        <groupId>com.jayway.restassured</groupId>
        <artifactId>spring-mock-mvc</artifactId>
-       <version>2.5.0</version>
+       <version>2.5.0</version>
        <scope>test</scope>
     </dependency>
 </dependencies>

That way, the plugin automatically sees that Rest Assured 3.x is present on the classpath @@ -1953,14 +1953,14 @@ endpoint, which should be verified.

import org.springframework.test.context.junit4.SpringRunner;
 import org.springframework.web.context.WebApplicationContext;
 
-@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SomeConfig.class, properties="some=property")
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SomeConfig.class, properties="some=property")
 public abstract class BaseTestClass {
 
-	@Autowired
+	@Autowired
 	WebApplicationContext context;
 
-	@Before
+	@Before
 	public void setup() {
 		RestAssuredMockMvc.webAppContextSetup(this.context);
 	}
@@ -1974,14 +1974,14 @@ similarly, as you might find in regular integration tests.

import org.springframework.test.context.junit4.SpringRunner;
 import org.springframework.web.context.WebApplicationContext;
 
-@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SomeConfig.class, properties="some=property")
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SomeConfig.class, properties="some=property")
 public abstract class BaseTestClass {
 
-	@LocalServerPort
+	@LocalServerPort
 	int port;
 
-	@Before
+	@Before
 	public void setup() {
 		RestAssured.baseURI = "http://localhost:" + this.port;
 	}
@@ -2088,13 +2088,13 @@ goal. Example:

</plugin>

Under Section 10.6, “Using the SCM Stub Downloader” you can find all possible configuration options that you can pass either via the <configuration><contractProperties> map, a system property -or an environment variable.

4.2.12 Maven Plugin and STS

If you see the following exception while using STS:

STS Exception

When you click on the error marker you should see something like this:

 plugin:1.1.0.M1:convert:default-convert:process-test-resources) org.apache.maven.plugin.PluginExecutionException: Execution default-convert of goal org.springframework.cloud:spring-
- cloud-contract-maven-plugin:1.1.0.M1:convert failed. at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:145) at
- org.eclipse.m2e.core.internal.embedder.MavenImpl.execute(MavenImpl.java:331) at org.eclipse.m2e.core.internal.embedder.MavenImpl$11.call(MavenImpl.java:1362) at
+or an environment variable.

4.2.12 Maven Plugin and STS

If you see the following exception while using STS:

STS Exception

When you click on the error marker you should see something like this:

 plugin:1.1.0.M1:convert:default-convert:process-test-resources) org.apache.maven.plugin.PluginExecutionException: Execution default-convert of goal org.springframework.cloud:spring-
+ cloud-contract-maven-plugin:1.1.0.M1:convert failed. at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:145) at
+ org.eclipse.m2e.core.internal.embedder.MavenImpl.execute(MavenImpl.java:331) at org.eclipse.m2e.core.internal.embedder.MavenImpl$11.call(MavenImpl.java:1362) at
 ...
- org.eclipse.core.internal.jobs.Worker.run(Worker.java:55) Caused by: java.lang.NullPointerException at
- org.eclipse.m2e.core.internal.builder.plexusbuildapi.EclipseIncrementalBuildContext.hasDelta(EclipseIncrementalBuildContext.java:53) at
- org.sonatype.plexus.build.incremental.ThreadBuildContext.hasDelta(ThreadBuildContext.java:59) at

In order to fix this issue, provide the following section in your pom.xml:

<build>
+ org.eclipse.core.internal.jobs.Worker.run(Worker.java:55) Caused by: java.lang.NullPointerException at
+ org.eclipse.m2e.core.internal.builder.plexusbuildapi.EclipseIncrementalBuildContext.hasDelta(EclipseIncrementalBuildContext.java:53) at
+ org.sonatype.plexus.build.incremental.ThreadBuildContext.hasDelta(ThreadBuildContext.java:59) at

In order to fix this issue, provide the following section in your pom.xml:

<build>
     <pluginManagement>
         <plugins>
             <!--This plugin's configuration is used to store Eclipse m2e settings
@@ -2134,13 +2134,13 @@ Please refer to the example below:

If yo Surefire plugin setup, like in the following example:

4.3 Stubs and Transitive Dependencies

The Maven and Gradle plugin that add the tasks that create the stubs jar for you. One problem that arises is that, when reusing the stubs, you can mistakenly import all of that stub’s dependencies. When building a Maven artifact, even though you have a couple -of different jars, all of them share one pom:

├── github-webhook-0.0.1.BUILD-20160903.075506-1-stubs.jar
-├── github-webhook-0.0.1.BUILD-20160903.075506-1-stubs.jar.sha1
-├── github-webhook-0.0.1.BUILD-20160903.075655-2-stubs.jar
-├── github-webhook-0.0.1.BUILD-20160903.075655-2-stubs.jar.sha1
-├── github-webhook-0.0.1.BUILD-SNAPSHOT.jar
-├── github-webhook-0.0.1.BUILD-SNAPSHOT.pom
-├── github-webhook-0.0.1.BUILD-SNAPSHOT-stubs.jar
+of different jars, all of them share one pom:

├── github-webhook-0.0.1.BUILD-20160903.075506-1-stubs.jar
+├── github-webhook-0.0.1.BUILD-20160903.075506-1-stubs.jar.sha1
+├── github-webhook-0.0.1.BUILD-20160903.075655-2-stubs.jar
+├── github-webhook-0.0.1.BUILD-20160903.075655-2-stubs.jar.sha1
+├── github-webhook-0.0.1.BUILD-SNAPSHOT.jar
+├── github-webhook-0.0.1.BUILD-SNAPSHOT.pom
+├── github-webhook-0.0.1.BUILD-SNAPSHOT-stubs.jar
 ├── ...
 └── ...

There are three possibilities of working with those dependencies so as not to have any issues with transitive dependencies:

  • Mark all application dependencies as optional
  • Create a separate artifactid for the stubs
  • Exclude dependencies on the consumer side

Mark all application dependencies as optional

If, in the github-webhook application, you mark all of your dependencies as optional, @@ -2254,12 +2254,12 @@ work.

ContractVerifierMessageExchange to send and receive messages that follow the contract. Then add @AutoConfigureMessageVerifier to your test. -Here’s an example:

@RunWith(SpringTestRunner.class)
-@SpringBootTest
-@AutoConfigureMessageVerifier
+Here’s an example:

@RunWith(SpringTestRunner.class)
+@SpringBootTest
+@AutoConfigureMessageVerifier
 public static class MessagingContractTests {
 
-  @Autowired
+  @Autowired
   private MessageVerifier verifier;
   ...
 }
[Note]Note

If your tests require stubs as well, then @AutoConfigureStubRunner includes the @@ -2704,7 +2704,7 @@ producer stubs.

The producer would setup the contr structure in your stubs jar.

└── META-INF
     └── com.example
         └── beer-api-producer-restdocs
-            └── 2.0.0
+            └── 2.0.0
                 ├── contracts
                 │   └── nested
                 │       └── contract2.groovy
@@ -2721,12 +2721,12 @@ the configuration files for the given HTTP server stub.

Spring Cloud Contr can extend, for WireMock - org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockHttpServerStubConfigurer. In the configure method you can provide your own, custom configuration for the given stub. The use case might be starting WireMock for the given artifact id, on an HTTPs port. Example:

WireMockHttpServerStubConfigurer implementation.  -

@CompileStatic
+

@CompileStatic
 static class HttpsForFraudDetection extends WireMockHttpServerStubConfigurer {
 
 	private static final Log log = LogFactory.getLog(HttpsForFraudDetection)
 
-	@Override
+	@Override
 	WireMockConfiguration configure(WireMockConfiguration httpStubConfiguration, HttpServerStubConfiguration httpServerStubConfiguration) {
 		if (httpServerStubConfiguration.stubConfiguration.artifactId == "fraudDetectionServer") {
 			int httpsPort = SocketUtils.findAvailableTcpPort()
@@ -2745,10 +2745,10 @@ case might be starting WireMock for the given artifact id, on an HTTPs port. Exa
                                   (default: stubs)
 --maxPort, --maxp <Integer>     Maximum port value to be assigned to
                                   the WireMock instance. Defaults to
-                                  15000 (default: 15000)
+                                  15000 (default: 15000)
 --minPort, --minp <Integer>     Minimum port value to be assigned to
                                   the WireMock instance. Defaults to
-                                  10000 (default: 10000)
+                                  10000 (default: 10000)
 -p, --password                  Password to user when connecting to
                                   repository
 --phost, --proxyHost            Proxy host to use for repository
@@ -2772,7 +2772,7 @@ case might be starting WireMock for the given artifact id, on an HTTPs port. Exa
         "url": "/ping"
     },
     "response": {
-        "status": 200,
+        "status": 200,
         "body": "pong",
         "headers": {
             "Content-Type": "text/plain"
@@ -2780,13 +2780,13 @@ case might be starting WireMock for the given artifact id, on an HTTPs port. Exa
     }
 }

Viewing registered mappings

Every stubbed collaborator exposes list of defined mappings under __/admin/ endpoint.

You can also use the mappingsOutputFolder property to dump the mappings to files. For annotation based approach it would look like this

@AutoConfigureStubRunner(ids="a.b.c:loanIssuance,a.b.c:fraudDetectionServer",
-mappingsOutputFolder = "target/outputmappings/")

and for the JUnit approach like this:

@ClassRule @Shared StubRunnerRule rule = new StubRunnerRule()
+mappingsOutputFolder = "target/outputmappings/")

and for the JUnit approach like this:

@ClassRule @Shared StubRunnerRule rule = new StubRunnerRule()
 			.repoRoot("http://some_url")
 			.downloadStub("a.b.c", "loanIssuance")
 			.downloadStub("a.b.c:fraudDetectionServer")
 			.withMappingsOutputFolder("target/outputmappings")

Then if you check out the folder target/outputmappings you would see the following structure

.
-├── fraudDetectionServer_13705
-└── loanIssuance_12255

That means that there were two stubs registered. fraudDetectionServer was registered at port 13705 +├── fraudDetectionServer_13705 +└── loanIssuance_12255

That means that there were two stubs registered. fraudDetectionServer was registered at port 13705 and loanIssuance at port 12255. If we take a look at one of the files we would see (for WireMock) mappings available for the given server:

[{
   "id" : "f9152eb9-bf77-4c38-8289-90be7d10d0d7",
@@ -2795,13 +2795,13 @@ mappings available for the given server:

["method" : "GET"
   },
   "response" : {
-    "status" : 200,
+    "status" : 200,
     "body" : "fraudDetectionServer"
   },
   "uuid" : "f9152eb9-bf77-4c38-8289-90be7d10d0d7"
 },
 ...
-]

Messaging Stubs

Depending on the provided Stub Runner dependency and the DSL the messaging routes are automatically set up.

6.4 Stub Runner JUnit Rule and Stub Runner JUnit5 Extension

Stub Runner comes with a JUnit rule thanks to which you can very easily download and run stubs for given group and artifact id:

@ClassRule
+]

Messaging Stubs

Depending on the provided Stub Runner dependency and the DSL the messaging routes are automatically set up.

6.4 Stub Runner JUnit Rule and Stub Runner JUnit5 Extension

Stub Runner comes with a JUnit rule thanks to which you can very easily download and run stubs for given group and artifact id:

@ClassRule
 public static StubRunnerRule rule = new StubRunnerRule().repoRoot(repoRoot())
 		.stubsMode(StubRunnerProperties.StubsMode.REMOTE)
 		.downloadStub("org.springframework.cloud.contract.verifier.stubs",
@@ -2809,8 +2809,8 @@ mappings available for the given server:

["org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer");
 
-@BeforeClass
-@AfterClass
+@BeforeClass
+@AfterClass
 public static void setupProps() {
 	System.clearProperty("stubrunner.repository.root");
 	System.clearProperty("stubrunner.classifier");
@@ -2824,14 +2824,14 @@ Check their import org.springframework.cloud.contract.spec.Contract;
 
-/**
+/**
  * Contract for finding registered stubs.
  *
  * @author Marcin Grzejszczak
- */
+ */
 public interface StubFinder extends StubTrigger {
 
-	/**
+	/**
 	 * For the given groupId and artifactId tries to find the matching URL of the running
 	 * stub.
 	 * @param groupId - might be null. In that case a search only via artifactId takes
@@ -2839,31 +2839,31 @@ Check their 
+	 */
 	URL findStubUrl(String groupId, String artifactId) throws StubNotFoundException;
 
-	/**
+	/**
 	 * For the given Ivy notation {@code [groupId]:artifactId:[version]:[classifier]}
 	 * tries to find the matching URL of the running stub. You can also pass only
 	 * {@code artifactId}.
 	 * @param ivyNotation - Ivy representation of the Maven artifact
 	 * @return URL of a running stub or throws exception if not found
 	 * @throws StubNotFoundException in case of not finding a stub
-	 */
+	 */
 	URL findStubUrl(String ivyNotation) throws StubNotFoundException;
 
-	/**
+	/**
 	 * @return all running stubs
-	 */
+	 */
 	RunningStubs findAllRunningStubs();
 
-	/**
+	/**
 	 * @return the list of Contracts
-	 */
+	 */
 	Map<StubConfiguration, Collection<Contract>> getContracts();
 
-}

Example of usage in Spock tests:

@ClassRule
-@Shared
+}

Example of usage in Spock tests:

@ClassRule
+@Shared
 StubRunnerRule rule = new StubRunnerRule()
 		.stubsMode(StubRunnerProperties.StubsMode.REMOTE)
 		.repoRoot(StubRunnerRuleSpec.getResource("/m2repo/repository").toURI().toString())
@@ -2892,7 +2892,7 @@ def 'should outp
 		def url = rule.findStubUrl('fraudDetectionServer')
 	then:
 		new File("target/outputmappingsforrule", "fraudDetectionServer_${url.port}").exists()
-}

Example of usage in JUnit tests:

	@Test
+}

Example of usage in JUnit tests:

	@Test
 	public void should_start_wiremock_servers() throws Exception {
 		// expect: 'WireMocks are running'
 		then(rule.findStubUrl("org.springframework.cloud.contract.verifier.stubs",
@@ -2925,7 +2925,7 @@ def 'should outp
 	}
 
 }

JUnit 5 Extension example:

// Visible for Junit
-@RegisterExtension
+@RegisterExtension
 static StubRunnerExtension stubRunnerExtension = new StubRunnerExtension()
 		.repoRoot(repoRoot()).stubsMode(StubRunnerProperties.StubsMode.REMOTE)
 		.downloadStub("org.springframework.cloud.contract.verifier.stubs",
@@ -2934,8 +2934,8 @@ def 'should outp
 				"org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")
 		.withMappingsOutputFolder("target/outputmappingsforrule");
 
-@BeforeAll
-@AfterAll
+@BeforeAll
+@AfterAll
 static void setupProps() {
 	System.clearProperty("stubrunner.repository.root");
 	System.clearProperty("stubrunner.classifier");
@@ -2953,16 +2953,16 @@ def 'should outp
 MessageVerifier interface to the rule builder (e.g. rule.messageVerifier(new MyMessageVerifier())).
 If you don’t do this, then whenever you try to send a message an exception will be thrown.

6.4.1 Maven settings

The stub downloader honors Maven settings for a different local repository folder. Authentication details for repositories and profiles are currently not taken into account, so you need to specify it using the properties mentioned above.

6.4.2 Providing fixed ports

You can also run your stubs on fixed ports. You can do it in two different ways. One is to pass it in the properties, and the other via fluent API of -JUnit rule.

6.4.3 Fluent API

When using the StubRunnerRule or StubRunnerExtension you can add a stub to download and then pass the port for the last downloaded stub.

@ClassRule
+JUnit rule.

6.4.3 Fluent API

When using the StubRunnerRule or StubRunnerExtension you can add a stub to download and then pass the port for the last downloaded stub.

@ClassRule
 public static StubRunnerRule rule = new StubRunnerRule().repoRoot(repoRoot())
 		.stubsMode(StubRunnerProperties.StubsMode.REMOTE)
 		.downloadStub("org.springframework.cloud.contract.verifier.stubs",
 				"loanIssuance")
-		.withPort(12345).downloadStub(
+		.withPort(12345).downloadStub(
 				"org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer:12346");
 
-@BeforeClass
-@AfterClass
+@BeforeClass
+@AfterClass
 public static void setupProps() {
 	System.clearProperty("stubrunner.repository.root");
 	System.clearProperty("stubrunner.classifier");
@@ -2971,28 +2971,28 @@ JUnit rule.

"fraudDetectionServer")) .isEqualTo(URI.create("http://localhost:12346").toURL());

6.4.4 Stub Runner with Spring

Sets up Spring configuration of the Stub Runner project.

By providing a list of stubs inside your configuration file the Stub Runner automatically downloads and registers in WireMock the selected stubs.

If you want to find the URL of your stubbed dependency you can autowire the StubFinder interface and use -its methods as presented below:

@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
-@SpringBootTest(properties = [" stubrunner.cloud.enabled=false",
+its methods as presented below:

@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
+@SpringBootTest(properties = [" stubrunner.cloud.enabled=false",
 		'foo=${stubrunner.runningstubs.fraudDetectionServer.port}',
-		'fooWithGroup=${stubrunner.runningstubs.org.springframework.cloud.contract.verifier.stubs.fraudDetectionServer.port}'])
-@AutoConfigureStubRunner(mappingsOutputFolder = "target/outputmappings/",
-		httpServerStubConfigurer = HttpsForFraudDetection)
-@ActiveProfiles("test")
+		'fooWithGroup=${stubrunner.runningstubs.org.springframework.cloud.contract.verifier.stubs.fraudDetectionServer.port}'])
+@AutoConfigureStubRunner(mappingsOutputFolder = "target/outputmappings/",
+		httpServerStubConfigurer = HttpsForFraudDetection)
+@ActiveProfiles("test")
 class StubRunnerConfigurationSpec extends Specification {
 
-	@Autowired
+	@Autowired
 	StubFinder stubFinder
-	@Autowired
+	@Autowired
 	Environment environment
-	@StubRunnerPort("fraudDetectionServer")
+	@StubRunnerPort("fraudDetectionServer")
 	int fraudDetectionServerPort
-	@StubRunnerPort("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")
+	@StubRunnerPort("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")
 	int fraudDetectionServerPortWithGroupId
-	@Value('${foo}')
+	@Value('${foo}')
 	Integer foo
 
-	@BeforeClass
-	@AfterClass
+	@BeforeClass
+	@AfterClass
 	void setupProps() {
 		System.clearProperty("stubrunner.repository.root")
 		System.clearProperty("stubrunner.classifier")
@@ -3044,18 +3044,18 @@ its methods as presented below:

int fraudPort = stubFinder.findAllRunningStubs().getPort("fraudDetectionServer")
 		expect:
-			fraudPort > 0
+			fraudPort > 0
 			environment.getProperty("foo", Integer) == fraudPort
 			environment.getProperty("fooWithGroup", Integer) == fraudPort
 			foo == fraudPort
 	}
 
-	@Issue("#573")
+	@Issue("#573")
 	def 'should be able to retrieve the port of a running stub via an annotation'() {
 		given:
 			int fraudPort = stubFinder.findAllRunningStubs().getPort("fraudDetectionServer")
 		expect:
-			fraudPort > 0
+			fraudPort > 0
 			fraudDetectionServerPort == fraudPort
 			fraudDetectionServerPortWithGroupId == fraudPort
 	}
@@ -3067,16 +3067,16 @@ its methods as presented below:

new File("target/outputmappings/", "fraudDetectionServer_${url.port}").exists()
 	}
 
-	@Configuration
-	@EnableAutoConfiguration
+	@Configuration
+	@EnableAutoConfiguration
 	static class Config {}
 
-	@CompileStatic
+	@CompileStatic
 	static class HttpsForFraudDetection extends WireMockHttpServerStubConfigurer {
 
 		private static final Log log = LogFactory.getLog(HttpsForFraudDetection)
 
-		@Override
+		@Override
 		WireMockConfiguration configure(WireMockConfiguration httpStubConfiguration, HttpServerStubConfiguration httpServerStubConfiguration) {
 			if (httpServerStubConfiguration.stubConfiguration.artifactId == "fraudDetectionServer") {
 				int httpsPort = SocketUtils.findAvailableTcpPort()
@@ -3103,9 +3103,9 @@ Below you can find an example of achieving the same result by setting values on
 for every registered WireMock server. Example for Stub Runner ids
  com.example:foo, com.example:bar.

  • stubrunner.runningstubs.foo.port
  • stubrunner.runningstubs.com.example.foo.port
  • stubrunner.runningstubs.bar.port
  • stubrunner.runningstubs.com.example.bar.port

Which you can reference in your code.

You can also use the @StubRunnerPort annotation to inject the port of a running stub. Value of the annotation can be the groupid:artifactid or just the artifactid. Example for Stub Runner ids -com.example:foo, com.example:bar.

@StubRunnerPort("foo")
+com.example:foo, com.example:bar.

@StubRunnerPort("foo")
 int fooPort;
-@StubRunnerPort("com.example:bar")
+@StubRunnerPort("com.example:bar")
 int barPort;

6.5 Stub Runner Spring Cloud

Stub Runner can integrate with Spring Cloud.

For real life examples you can check the

6.5.1 Stubbing Service Discovery

The most important feature of Stub Runner Spring Cloud is the fact that it’s stubbing

  • DiscoveryClient
  • Ribbon ServerList

that means that regardless of the fact whether you’re using Zookeeper, Consul, Eureka or anything else, you don’t need that in your tests. We’re starting WireMock instances of your dependencies and we’re telling your application whenever you’re using Feign, load balanced RestTemplate or DiscoveryClient directly, to call those stubbed servers instead of calling the real Service Discovery tool.

For example this test will pass

def 'should make service discovery work'() {
@@ -3144,12 +3144,12 @@ or a subdirectory called config or in spring cloud stubrunner from your terminal window to start
-the Stub Runner server. It will be available at port 8750.

6.6.2 Endpoints

HTTP

  • GET /stubs - returns a list of all running stubs in ivy:integer notation
  • GET /stubs/{ivy} - returns a port for the given ivy notation (when calling the endpoint ivy can also be artifactId only)

Messaging

For Messaging

  • GET /triggers - returns a list of all running labels in ivy : [ label1, label2 …​] notation
  • POST /triggers/{label} - executes a trigger with label
  • POST /triggers/{ivy}/{label} - executes a trigger with label for the given ivy notation (when calling the endpoint ivy can also be artifactId only)

6.6.3 Example

@ContextConfiguration(classes = StubRunnerBoot, loader = SpringBootContextLoader)
-@SpringBootTest(properties = "spring.cloud.zookeeper.enabled=false")
-@ActiveProfiles("test")
+the Stub Runner server. It will be available at port 8750.

6.6.2 Endpoints

HTTP

  • GET /stubs - returns a list of all running stubs in ivy:integer notation
  • GET /stubs/{ivy} - returns a port for the given ivy notation (when calling the endpoint ivy can also be artifactId only)

Messaging

For Messaging

  • GET /triggers - returns a list of all running labels in ivy : [ label1, label2 …​] notation
  • POST /triggers/{label} - executes a trigger with label
  • POST /triggers/{ivy}/{label} - executes a trigger with label for the given ivy notation (when calling the endpoint ivy can also be artifactId only)

6.6.3 Example

@ContextConfiguration(classes = StubRunnerBoot, loader = SpringBootContextLoader)
+@SpringBootTest(properties = "spring.cloud.zookeeper.enabled=false")
+@ActiveProfiles("test")
 class StubRunnerBootSpec extends Specification {
 
-	@Autowired
+	@Autowired
 	StubRunning stubRunning
 
 	def setup() {
@@ -3169,8 +3169,8 @@ the Stub Runner server. It will be available at port 8750<
 		when:
 			def response = RestAssuredMockMvc.get("/stubs/${stubId}")
 		then:
-			response.statusCode == 200
-			Integer.valueOf(response.body.asString()) > 0
+			response.statusCode == 200
+			Integer.valueOf(response.body.asString()) > 0
 		where:
 			stubId << ['org.springframework.cloud.contract.verifier.stubs:bootService:+:stubs',
 					   'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs',
@@ -3183,7 +3183,7 @@ the Stub Runner server. It will be available at port 8750<
 		when:
 			def response = RestAssuredMockMvc.get("/stubs/a:b:c:d")
 		then:
-			response.statusCode == 404
+			response.statusCode == 404
 	}
 
 	def 'should return a list of messaging labels that can be triggered when version and classifier are passed'() {
@@ -3201,9 +3201,9 @@ the Stub Runner server. It will be available at port 8750<
 		when:
 			def response = RestAssuredMockMvc.post("/triggers/delete_book")
 		then:
-			response.statusCode == 200
+			response.statusCode == 200
 		and:
-			1 * stubRunning.trigger('delete_book')
+			1 * stubRunning.trigger('delete_book')
 	}
 
 	def 'should trigger a messaging label for a stub with [#stubId] ivy notation'() {
@@ -3213,9 +3213,9 @@ the Stub Runner server. It will be available at port 8750<
 		when:
 			def response = RestAssuredMockMvc.post("/triggers/$stubId/delete_book")
 		then:
-			response.statusCode == 200
+			response.statusCode == 200
 		and:
-			1 * stubRunning.trigger(stubId, 'delete_book')
+			1 * stubRunning.trigger(stubId, 'delete_book')
 		where:
 			stubId << ['org.springframework.cloud.contract.verifier.stubs:bootService:stubs', 'org.springframework.cloud.contract.verifier.stubs:bootService', 'bootService']
 	}
@@ -3240,10 +3240,10 @@ the Stub Runner server. It will be available at port 8750<
  of testing scenarios.

The problem with this approach is such that if you’re doing microservices most likely you’re using a service discovery tool. Stub Runner Boot allows you to solve this issue by starting the required stubs and register them in a service discovery tool. Let’s take a look at an example of - such a setup with Eureka. Let’s assume that Eureka was already running.

@SpringBootApplication
-@EnableStubRunnerServer
-@EnableEurekaClient
-@AutoConfigureStubRunner
+ such a setup with Eureka. Let’s assume that Eureka was already running.

@SpringBootApplication
+@EnableStubRunnerServer
+@EnableEurekaClient
+@AutoConfigureStubRunner
 public class StubRunnerBootEurekaExample {
 
 	public static void main(String[] args) {
@@ -3253,17 +3253,17 @@ the Stub Runner server. It will be available at port 8750<
 }

As you can see we want to start a Stub Runner Boot server @EnableStubRunnerServer, enable Eureka client @EnableEurekaClient and we want to have the stub runner feature turned on @AutoConfigureStubRunner.

Now let’s assume that we want to start this application so that the stubs get automatically registered. We can do it by running the app java -jar ${SYSTEM_PROPS} stub-runner-boot-eureka-example.jar where - ${SYSTEM_PROPS} would contain the following list of properties

* -Dstubrunner.repositoryRoot=https://repo.spring.io/snapshot (1)
-* -Dstubrunner.cloud.stubbed.discovery.enabled=false (2)
+ ${SYSTEM_PROPS} would contain the following list of properties

* -Dstubrunner.repositoryRoot=https://repo.spring.io/snapshot (1)
+* -Dstubrunner.cloud.stubbed.discovery.enabled=false (2)
 * -Dstubrunner.ids=org.springframework.cloud.contract.verifier.stubs:loanIssuance,org.
 * springframework.cloud.contract.verifier.stubs:fraudDetectionServer,org.springframework.
-* cloud.contract.verifier.stubs:bootService (3)
+* cloud.contract.verifier.stubs:bootService (3)
 * -Dstubrunner.idsToServiceIds.fraudDetectionServer=
-* someNameThatShouldMapFraudDetectionServer (4)
+* someNameThatShouldMapFraudDetectionServer (4)
 *
-* (1) - we tell Stub Runner where all the stubs reside (2) - we don't want the default
+* (1) - we tell Stub Runner where all the stubs reside (2) - we don't want the default
 * behaviour where the discovery service is stubbed. That's why the stub registration will
-* be picked (3) - we provide a list of stubs to download (4) - we provide a list of

That way your deployed application can send requests to started WireMock servers via the service +* be picked (3) - we provide a list of stubs to download (4) - we provide a list of

That way your deployed application can send requests to started WireMock servers via the service discovery. Most likely points 1-3 could be set by default in application.yml cause they are not likely to change. That way you can provide only the list of stubs to download whenever you start the Stub Runner Boot.

6.7 Stubs Per Consumer

There are cases in which 2 consumers of the same endpoint want to have 2 different responses.

[Tip]Tip

This approach also allows you to immediately know which consumer is using which part of your API. @@ -3299,22 +3299,22 @@ if it contains the subfolder with name of the consumer in the path only then wil └── foo-consumer ├── bookReturnedForFoo.groovy └── shouldCallFoo.groovy

Being the bar-consumer consumer you can either set the spring.application.name or the stubrunner.consumer-name to bar-consumer -Or set the test as follows:

@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
-@SpringBootTest(properties = ["spring.application.name=bar-consumer"])
-@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers",
+Or set the test as follows:

@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
+@SpringBootTest(properties = ["spring.application.name=bar-consumer"])
+@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers",
 		repositoryRoot = "classpath:m2repo/repository/",
 		stubsMode = StubRunnerProperties.StubsMode.REMOTE,
-		stubsPerConsumer = true)
+		stubsPerConsumer = true)
 class StubRunnerStubsPerConsumerSpec extends Specification {
 ...
 }

Then only the stubs registered under a path that contains the bar-consumer in its name (i.e. those from the -src/test/resources/contracts/bar-consumer/some/contracts/…​ folder) will be allowed to be referenced.

Or set the consumer name explicitly

@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
-@SpringBootTest
-@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers",
+src/test/resources/contracts/bar-consumer/some/contracts/…​ folder) will be allowed to be referenced.

Or set the consumer name explicitly

@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
+@SpringBootTest
+@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers",
 		repositoryRoot = "classpath:m2repo/repository/",
 		consumerName = "foo-consumer",
 		stubsMode = StubRunnerProperties.StubsMode.REMOTE,
-		stubsPerConsumer = true)
+		stubsPerConsumer = true)
 class StubRunnerStubsPerConsumerWithConsumerNameSpec extends Specification {
 ...
 }

Then only the stubs registered under a path that contains the foo-consumer in its name (i.e. those from the @@ -3352,9 +3352,9 @@ $ STUBRUNNER_REPOSITORY_ROOT=# Run the docker with Stub Runner Boot $ docker run --rm -e "STUBRUNNER_IDS=${STUBRUNNER_IDS}" -e "STUBRUNNER_REPOSITORY_ROOT=${STUBRUNNER_REPOSITORY_ROOT}" -e "STUBRUNNER_STUBS_MODE=REMOTE" -p "${STUBRUNNER_PORT}:${STUBRUNNER_PORT}" -p "9876:9876" springcloud/spring-cloud-contract-stub-runner:"${SC_CONTRACT_DOCKER_VERSION}"

What’s happening is that

  • a standalone Stub Runner application got started
  • it downloaded the stub with coordinates com.example:bookstore:0.0.1.RELEASE:stubs on port 9876
  • it got downloaded from Artifactory running at http://192.168.0.100:8081/artifactory/libs-release-local
  • after a while Stub Runner will be running on port 8083
  • and the stubs will be running at port 9876

On the server side we built a stateful stub. Let’s use curl to assert that the stubs are setup properly.

# let's execute the first request (no response is returned)
-$ curl -H "Content-Type:application/json" -X POST --data '{ "title" : "Title", "genre" : "Genre", "description" : "Description", "author" : "Author", "publisher" : "Publisher", "pages" : 100, "image_url" : "https://d213dhlpdb53mu.cloudfront.net/assets/pivotal-square-logo-41418bd391196c3022f3cd9f3959b3f6d7764c47873d858583384e759c7db435.svg", "buy_url" : "https://pivotal.io" }' http://localhost:9876/api/books
+$ curl -H "Content-Type:application/json" -X POST --data '{ "title" : "Title", "genre" : "Genre", "description" : "Description", "author" : "Author", "publisher" : "Publisher", "pages" : 100, "image_url" : "https://d213dhlpdb53mu.cloudfront.net/assets/pivotal-square-logo-41418bd391196c3022f3cd9f3959b3f6d7764c47873d858583384e759c7db435.svg", "buy_url" : "https://pivotal.io" }' http://localhost:9876/api/books
 # Now time for the second request
-$ curl -X GET http://localhost:9876/api/books
+$ curl -X GET http://localhost:9876/api/books
 # You will receive contents of the JSON
[Important]Important

If you want use the stubs that you have built locally, on your host, then you should pass the environment variable -e STUBRUNNER_STUBS_MODE=LOCAL and mount the volume of your local m2 -v "${HOME}/.m2/:/root/.m2:ro"

7. Stub Runner for Messaging

Stub Runner can run the published stubs in memory. It can integrate with the following @@ -3366,14 +3366,14 @@ That way the only remaining framework is Spring AMQP.

import java.util.Collection; import java.util.Map; -/** +/** * Contract for triggering stub messages. * * @author Marcin Grzejszczak - */ + */ public interface StubTrigger { - /** + /** * Triggers an event by a given label for a given {@code groupid:artifactid} notation. * You can use only {@code artifactId} too. * @@ -3381,30 +3381,30 @@ That way the only remaining framework is Spring AMQP.

+ */ boolean trigger(String ivyNotation, String labelName); - /** + /** * Triggers an event by a given label. * * Feature related to messaging. * @param labelName name of the label to trigger * @return true - if managed to run a trigger - */ + */ boolean trigger(String labelName); - /** + /** * Triggers all possible events. * * Feature related to messaging. * @return true - if managed to run a trigger - */ + */ boolean trigger(); - /** + /** * Feature related to messaging. * @return a mapping of ivy notation of a dependency to all the labels it has. - */ + */ Map<String, Collection<String>> labels(); }

For convenience, the StubFinder interface extends StubTrigger, so you only need one @@ -3419,9 +3419,9 @@ Remember to annotate your test class with @AutoConfigureSt └── accurest └── stubs └── camelService - ├── 0.0.1-SNAPSHOT - │   ├── camelService-0.0.1-SNAPSHOT.pom - │   ├── camelService-0.0.1-SNAPSHOT-stubs.jar + ├── 0.0.1-SNAPSHOT + │   ├── camelService-0.0.1-SNAPSHOT.pom + │   ├── camelService-0.0.1-SNAPSHOT-stubs.jar │   └── maven-metadata-local.xml └── maven-metadata-local.xml

And the stubs contain the following structure:

├── META-INF
 │   └── MANIFEST.MF
@@ -3462,10 +3462,10 @@ Remember to annotate your test class with @AutoConfigureSt
 			header('BOOK-NAME', 'foo')
 		}
 	}
-}

Scenario 1 (no input message)

So as to trigger a message via the return_book_1 label we’ll use the StubTigger interface as follows

stubFinder.trigger('return_book_1')

Next we’ll want to listen to the output of the message sent to jms:output

Exchange receivedMessage = consumerTemplate.receive('jms:output', 5000)

And the received message would pass the following assertions

receivedMessage != null
+}

Scenario 1 (no input message)

So as to trigger a message via the return_book_1 label we’ll use the StubTigger interface as follows

stubFinder.trigger('return_book_1')

Next we’ll want to listen to the output of the message sent to jms:output

Exchange receivedMessage = consumerTemplate.receive('jms:output', 5000)

And the received message would pass the following assertions

receivedMessage != null
 assertThatBodyContainsBookNameFoo(receivedMessage.in.body)
 receivedMessage.in.headers.get('BOOK-NAME') == 'foo'

Scenario 2 (output triggered by input)

Since the route is set for you it’s enough to just send a message to the jms:output destination.

producerTemplate.
-		sendBodyAndHeaders('jms:input', new BookReturned('foo'), [sample: 'header'])

Next we’ll want to listen to the output of the message sent to jms:output

Exchange receivedMessage = consumerTemplate.receive('jms:output', 5000)

And the received message would pass the following assertions

receivedMessage != null
+		sendBodyAndHeaders('jms:input', new BookReturned('foo'), [sample: 'header'])

Next we’ll want to listen to the output of the message sent to jms:output

Exchange receivedMessage = consumerTemplate.receive('jms:output', 5000)

And the received message would pass the following assertions

receivedMessage != null
 assertThatBodyContainsBookNameFoo(receivedMessage.in.body)
 receivedMessage.in.headers.get('BOOK-NAME') == 'foo'

Scenario 3 (input with no output)

Since the route is set for you it’s enough to just send a message to the jms:output destination.

producerTemplate.
 		sendBodyAndHeaders('jms:delete', new BookReturned('foo'), [sample: 'header'])

7.3 Stub Runner Integration

Spring Cloud Contract Verifier Stub Runner’s messaging module gives you an easy way to @@ -3480,9 +3480,9 @@ classpath. Remember to annotate your test class with @Auto └── accurest └── stubs └── integrationService - ├── 0.0.1-SNAPSHOT - │   ├── integrationService-0.0.1-SNAPSHOT.pom - │   ├── integrationService-0.0.1-SNAPSHOT-stubs.jar + ├── 0.0.1-SNAPSHOT + │   ├── integrationService-0.0.1-SNAPSHOT.pom + │   ├── integrationService-0.0.1-SNAPSHOT-stubs.jar │   └── maven-metadata-local.xml └── maven-metadata-local.xml

Further assume the stubs contain the following structure:

├── META-INF
 │   └── MANIFEST.MF
@@ -3523,7 +3523,7 @@ classpath. Remember to annotate your test class with @Auto
 			header('BOOK-NAME', 'foo')
 		}
 	}
-}

and the following Spring Integration Route:

<?xml version="1.0" encoding="UTF-8"?>
+}

and the following Spring Integration Route:

<?xml version="1.0" encoding="UTF-8"?>
 <beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 			 xmlns:beans="http://www.springframework.org/schema/beans"
 			 xmlns="http://www.springframework.org/schema/integration"
@@ -3570,9 +3570,9 @@ property.

Assume that you have the following Maven repository with a deplo └── accurest └── stubs └── streamService - ├── 0.0.1-SNAPSHOT - │   ├── streamService-0.0.1-SNAPSHOT.pom - │   ├── streamService-0.0.1-SNAPSHOT-stubs.jar + ├── 0.0.1-SNAPSHOT + │   ├── streamService-0.0.1-SNAPSHOT.pom + │   ├── streamService-0.0.1-SNAPSHOT-stubs.jar │   └── maven-metadata-local.xml └── maven-metadata-local.xml

Further assume the stubs contain the following structure:

├── META-INF
 │   └── MANIFEST.MF
@@ -3606,7 +3606,7 @@ property.

Assume that you have the following Maven repository with a deplo headers { header('BOOK-NAME', 'foo') } } }

Now consider the following Spring configuration:

stubrunner.repositoryRoot: classpath:m2repo/repository/
-stubrunner.ids: org.springframework.cloud.contract.verifier.stubs:streamService:0.0.1-SNAPSHOT:stubs
+stubrunner.ids: org.springframework.cloud.contract.verifier.stubs:streamService:0.0.1-SNAPSHOT:stubs
 stubrunner.stubs-mode: remote
 spring:
   cloud:
@@ -3618,7 +3618,7 @@ property.

Assume that you have the following Maven repository with a deplo destination: bookStorage server: - port: 0 + port: 0 debug: true

These examples lend themselves to three scenarios:

Scenario 1 (no input message)

To trigger a message via the return_book_1 label, use the StubTrigger interface as follows:

stubFinder.trigger('return_book_1')

To listen to the output of the message sent to a channel whose destination is @@ -3651,9 +3651,9 @@ to disable them explicitly by setting the stubrunner.stre └── com └── example └── spring-cloud-contract-amqp-test - ├── 0.4.0-SNAPSHOT - │   ├── spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT.pom - │   ├── spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT-stubs.jar + ├── 0.4.0-SNAPSHOT + │   ├── spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT.pom + │   ├── spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT-stubs.jar │   └── maven-metadata-local.xml └── maven-metadata-local.xml

Further assume that the stubs contain the following structure:

├── META-INF
 │   └── MANIFEST.MF
@@ -3678,25 +3678,25 @@ to disable them explicitly by setting the  stubrunner.stre
 		}
 		// the body of the output message
 		body([
-				id  : $(consumer(9), producer(regex("[0-9]+"))),
+				id  : $(consumer(9), producer(regex("[0-9]+"))),
 				name: "me"
 		])
 	}
 }

Now consider the following Spring configuration:

stubrunner:
   repositoryRoot: classpath:m2repo/repository/
-  ids: org.springframework.cloud.contract.verifier.stubs.amqp:spring-cloud-contract-amqp-test:0.4.0-SNAPSHOT:stubs
+  ids: org.springframework.cloud.contract.verifier.stubs.amqp:spring-cloud-contract-amqp-test:0.4.0-SNAPSHOT:stubs
   stubs-mode: remote
   amqp:
     enabled: true
 server:
-  port: 0

Triggering the message

To trigger a message using the contract above, use the StubTrigger interface as + port: 0

Triggering the message

To trigger a message using the contract above, use the StubTrigger interface as follows:

stubTrigger.trigger("contract-test.person.created.event")

The message has a destination of contract-test.exchange, so the Spring AMQP stub runner -integration looks for bindings related to this exchange.

@Bean
+integration looks for bindings related to this exchange.

@Bean
 public Binding binding() {
 	return BindingBuilder.bind(new Queue("test.queue"))
 			.to(new DirectExchange("contract-test.exchange")).with("#");
 }

The binding definition binds the queue test.queue. As a result, the following listener -definition is matched and invoked with the contract message.

@Bean
+definition is matched and invoked with the contract message.

@Bean
 public SimpleMessageListenerContainer simpleMessageListenerContainer(
 		ConnectionFactory connectionFactory,
 		MessageListenerAdapter listenerAdapter) {
@@ -3706,7 +3706,7 @@ definition is matched and invoked with the contract message.

return container;
-}

Also, the following annotated listener matches and is invoked:

@RabbitListener(bindings = @QueueBinding(value = @Queue("test.queue"), exchange = @Exchange(value = "contract-test.exchange", ignoreDeclarationExceptions = "true")))
+}

Also, the following annotated listener matches and is invoked:

@RabbitListener(bindings = @QueueBinding(value = @Queue("test.queue"), exchange = @Exchange(value = "contract-test.exchange", ignoreDeclarationExceptions = "true")))
 public void handlePerson(Person person) {
 	this.person = person;
 }
[Note]Note

The message is directly handed over to the onMessage method of the @@ -3929,7 +3929,7 @@ Contract.make { body(fileAsBytes("request.pdf")) } response { - status 200 + status 200 body(fileAsBytes("response.pdf")) headers { contentType(applicationOctetStream()) @@ -3965,13 +3965,13 @@ response: // with following response after receiving request // specified in "request" part above). response { - status 200 + status 200 //... } // Contract priority, which can be used for overriding // contracts (1 is highest). Priority is optional. - priority 1 + priority 1 }

YAML. 

priority: 8
@@ -3994,7 +3994,7 @@ same information is mandatory in request definition of the Contract.

Gr response { //... - status 200 + status 200 } }

YAML.  @@ -4012,7 +4012,7 @@ the recommended way, as doing so makes the tests ho response { //... - status 200 + status 200 } }

YAML.  @@ -4035,7 +4035,7 @@ the recommended way, as doing so makes the tests ho // If a simple literal is used as value // default matcher function is used (equalTo) - parameter 'limit': 100 + parameter 'limit': 100 // `equalTo` function simply compares passed value // using identity operator (==). @@ -4047,11 +4047,11 @@ the recommended way, as doing so makes the tests ho // `matching` function tests parameter // against passed regular expression. - parameter 'offset': value(consumer(matching("[0-9]+")), producer(123)) + parameter 'offset': value(consumer(matching("[0-9]+")), producer(123)) // `notMatching` functions tests if parameter // does not match passed regular expression. - parameter 'loginStartsWith': value(consumer(notMatching(".{0,2}")), producer(3)) + parameter 'loginStartsWith': value(consumer(notMatching(".{0,2}")), producer(3)) } } @@ -4060,7 +4060,7 @@ the recommended way, as doing so makes the tests ho response { //... - status 200 + status 200 } }

YAML.  @@ -4136,7 +4136,7 @@ response: response { //... - status 200 + status 200 } }

YAML.  @@ -4164,7 +4164,7 @@ headers: response { //... - status 200 + status 200 } }

YAML.  @@ -4187,7 +4187,7 @@ cookies: response { //... - status 200 + status 200 } }

YAML.  @@ -4251,7 +4251,7 @@ parametrization of either fileName or "/multipart"); // then: - assertThat(response.statusCode()).isEqualTo(200);

The WireMock stub is as follows:

			'''
+ assertThat(response.statusCode()).isEqualTo(200);

The WireMock stub is as follows:

			'''
 {
   "request" : {
 	"url" : "/multipart",
@@ -4270,7 +4270,7 @@ parametrization of either fileName or } ]
   },
   "response" : {
-	"status" : 200,
+	"status" : 200,
 	"transformers" : [ "response-template", "foo-transformer" ]
   }
 }
@@ -4317,7 +4317,7 @@ for requests that follow a given pattern. Also, you can use regular expressions
 need to use patterns and not exact values both for your test and your server side tests.

The following example shows how to use regular expressions to write a request:

org.springframework.cloud.contract.spec.Contract.make {
 	request {
 		method('GET')
-		url $(consumer(~/\/[0-9]{2}/), producer('/12'))
+		url $(consumer(~/\/[0-9]{2}/), producer('/12'))
 	}
 	response {
 		status OK()
@@ -4388,7 +4388,7 @@ use in your contracts, as shown in the following example:

protected static final Pattern NON_EMPTY = Pattern.compile(/[\S\s]+/)
 protected static final Pattern NON_BLANK = Pattern.compile(/^\s*\S[\S\s]*/)
 protected static final Pattern ISO8601_WITH_OFFSET = Pattern.
-		compile(/([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.\d{3})?(Z|[+-][01]\d:[0-5]\d)/)
+		compile(/([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.\d{3})?(Z|[+-][01]\d:[0-5]\d)/)
 
 protected static Pattern anyOf(String... values) {
 	return Pattern.compile(values.collect({ "^$it\$" }).join("|"))
@@ -4469,7 +4469,7 @@ RegexProperty nonEmpty() {
 RegexProperty nonBlank() {
 	return new RegexProperty(NON_BLANK).asString()
 }

In your contract, you can use it as shown in the following example:

Contract dslWithOptionalsInString = Contract.make {
-	priority 1
+	priority 1
 	request {
 		method POST()
 		url '/users/password'
@@ -4482,7 +4482,7 @@ RegexProperty nonBlank() {
 		)
 	}
 	response {
-		status 404
+		status 404
 		headers {
 			contentType(applicationJson())
 		}
@@ -4564,7 +4564,7 @@ T anyOf(String... values)

and this is an example of how you can referenc }

8.5.3 Passing Optional Parameters

[Important]Important

This section is valid only for Groovy DSL. Check out the Section 8.5.7, “Dynamic Properties in the Matchers Sections” section for YAML examples of a similar feature.

It is possible to provide optional parameters in your contract. However, you can provide optional parameters only for the following:

  • STUB side of the Request
  • TEST side of the Response

The following example shows how to provide optional parameters:

org.springframework.cloud.contract.spec.Contract.make {
-	priority 1
+	priority 1
 	request {
 		method 'POST'
 		url '/users/password'
@@ -4577,7 +4577,7 @@ optional parameters only for the following:

    404 + status 404 headers { header 'Content-Type': 'application/json' } @@ -4597,7 +4597,7 @@ expression that must be present 0 or more times.

    If you use Spock for, the .post("/users/password") then: - response.statusCode == 404 + response.statusCode == 404 response.header('Content-Type') == 'application/json' and: DocumentContext parsedJson = JsonPath.parse(response.body.asString()) @@ -4619,13 +4619,13 @@ expression that must be present 0 or more times.

    If you use Spock for, the } }, "response" : { - "status" : 404, - "body" : "{\\"code\\":\\"123123\\",\\"message\\":\\"User not found by email == [not.existing@user.com]\\"}", + "status" : 404, + "body" : "{\\"code\\":\\"123123\\",\\"message\\":\\"User not found by email == [not.existing@user.com]\\"}", "headers" : { "Content-Type" : "application/json" } }, - "priority" : 1 + "priority" : 1 } '''

8.5.4 Executing Custom Methods on the Server Side

[Important]Important

This section is valid only for Groovy DSL. Check out the Section 8.5.7, “Dynamic Properties in the Matchers Sections” section for YAML examples of a similar feature.

You can define a method call that executes on the server side during the test. Such a @@ -4657,7 +4657,7 @@ following code shows an example of the contract portion of the test case:

void isProperCorrelationId(Integer correlationId) { - assert correlationId == 123456 + assert correlationId == 123456 } void isEmpty(String value) { @@ -4691,7 +4691,7 @@ It should resemble the following code:

"/something");
 
 // then:
- assertThat(response.statusCode()).isEqualTo(200);

8.5.5 Referencing the Request from the Response

The best situation is to provide fixed values, but sometimes you need to reference a + assertThat(response.statusCode()).isEqualTo(200);

8.5.5 Referencing the Request from the Response

The best situation is to provide fixed values, but sometimes you need to reference a request in your response.

If you’re writing contracts using Groovy DSL, you can use the fromRequest() method, which lets you reference a bunch of elements from the HTTP request. You can use the following options:

  • fromRequest().url(): Returns the request URL and query parameters.
  • fromRequest().query(String key): Returns the first query parameter with a given name.
  • fromRequest().query(String key, int index): Returns the nth query parameter with a @@ -4747,7 +4747,7 @@ response: .get("/api/v1/xxxx"); // then: - assertThat(response.statusCode()).isEqualTo(200); + assertThat(response.statusCode()).isEqualTo(200); assertThat(response.header("Authorization")).isEqualTo("foo secret bar"); // and: DocumentContext parsedJson = JsonPath.parse(response.getBody().asString()); @@ -4758,7 +4758,7 @@ response: assertThatJson(parsedJson).field("['param']").isEqualTo("bar"); assertThatJson(parsedJson).field("['paramIndex']").isEqualTo("bar2"); assertThatJson(parsedJson).field("['pathIndex']").isEqualTo("v1"); - assertThatJson(parsedJson).field("['responseBaz']").isEqualTo(5); + assertThatJson(parsedJson).field("['responseBaz']").isEqualTo(5); assertThatJson(parsedJson).field("['responseFoo']").isEqualTo("bar"); assertThatJson(parsedJson).field("['url']").isEqualTo("/api/v1/xxxx?foo=bar&foo=bar2"); assertThatJson(parsedJson).field("['responseBaz2']").isEqualTo("Bla bla bar bla bla");

    As you can see, elements from the request have been properly referenced in the response.

    The generated WireMock stub should resemble the following example:

    {
    @@ -4782,7 +4782,7 @@ response:
         } ]
       },
       "response" : {
    -    "status" : 200,
    +    "status" : 200,
         "body" : "{\"authorization\":\"{{{request.headers.Authorization.[0]}}}\",\"path\":\"{{{request.path}}}\",\"responseBaz\":{{{jsonpath this '$.baz'}}} ,\"param\":\"{{{request.query.foo.[0]}}}\",\"pathIndex\":\"{{{request.path.[1]}}}\",\"responseBaz2\":\"Bla bla {{{jsonpath this '$.foo'}}} bla bla\",\"responseFoo\":\"{{{jsonpath this '$.foo'}}}\",\"authorization2\":\"{{{request.headers.Authorization.[1]}}}\",\"fullBody\":\"{{{escapejsonbody}}}\",\"url\":\"{{{request.url}}}\",\"paramIndex\":\"{{{request.query.foo.[1]}}}\"}",
         "headers" : {
           "Authorization" : "{{{request.headers.Authorization.[0]}}};foo"
    @@ -4800,7 +4800,7 @@ in sending the following response body:

    "authorization2" : "secret2",
       "fullBody" : "{\"foo\":\"bar\",\"baz\":5}",
       "responseFoo" : "bar",
    -  "responseBaz" : 5,
    +  "responseBaz" : 5,
       "responseBaz2" : "Bla bla bar bla bla"
     }
    [Important]Important

    This feature works only with WireMock having a version greater than or equal to 2.5.1. The Spring Cloud Contract Verifier uses WireMock’s @@ -4834,11 +4834,11 @@ org.springframework.cloud.contract.stubrunner.TestCustomYamlContractConverter

    import com.github.tomakehurst.wiremock.extension.Extension -/** +/** * Extension that registers the default transformer and the custom one - */ + */ class TestWireMockExtensions implements WireMockExtensions { - @Override + @Override List<Extension> extensions() { return [ new DefaultResponseTransformer(), @@ -4849,7 +4849,7 @@ org.springframework.cloud.contract.stubrunner.TestCustomYamlContractConverter

    class CustomExtension implements Extension { - @Override + @Override String getName() { return "foo-transformer" } @@ -4893,9 +4893,9 @@ email, url, uuid, iso_date, iso_date_time, iso_time, iso_8601_with_offset, non_e method 'GET' urlPath '/get' body([ - duck : 123, + duck : 123, alpha : 'abc', - number : 123, + number : 123, aBoolean : true, date : '2017-01-01', dateTime : '2017-01-01T01:23:45', @@ -4925,13 +4925,13 @@ email, url, uuid, iso_date, iso_date_time, iso_time, iso_8601_with_offset, non_e response { status OK() body([ - duck : 123, + duck : 123, alpha : 'abc', - number : 123, - positiveInteger : 1234567890, - negativeInteger : -1234567890, - positiveDecimalNumber: 123.4567890, - negativeDecimalNumber: -123.4567890, + number : 123, + positiveInteger : 1234567890, + negativeInteger : -1234567890, + positiveDecimalNumber: 123.4567890, + negativeDecimalNumber: -123.4567890, aBoolean : true, date : '2017-01-01', dateTime : '2017-01-01T01:23:45', @@ -4939,13 +4939,13 @@ email, url, uuid, iso_date, iso_date_time, iso_time, iso_8601_with_offset, non_e valueWithoutAMatcher : 'foo', valueWithTypeMatch : 'string', valueWithMin : [ - 1, 2, 3 + 1, 2, 3 ], valueWithMax : [ - 1, 2, 3 + 1, 2, 3 ], valueWithMinMax : [ - 1, 2, 3 + 1, 2, 3 ], valueWithMinEmpty : [], valueWithMaxEmpty : [], @@ -4976,24 +4976,24 @@ email, url, uuid, iso_date, iso_date_time, iso_time, iso_8601_with_offset, non_e jsonPath('$.valueWithTypeMatch', byType()) jsonPath('$.valueWithMin', byType { // results in verification of size of array (min 1) - minOccurrence(1) + minOccurrence(1) }) jsonPath('$.valueWithMax', byType { // results in verification of size of array (max 3) - maxOccurrence(3) + maxOccurrence(3) }) jsonPath('$.valueWithMinMax', byType { // results in verification of size of array (min 1 & max 3) - minOccurrence(1) - maxOccurrence(3) + minOccurrence(1) + maxOccurrence(3) }) jsonPath('$.valueWithMinEmpty', byType { // results in verification of size of array (min 0) - minOccurrence(0) + minOccurrence(0) }) jsonPath('$.valueWithMaxEmpty', byType { // results in verification of size of array (max 0) - maxOccurrence(0) + maxOccurrence(0) }) // will execute a method `assertThatValueIsANumber` jsonPath('$.duck', byCommand('assertThatValueIsANumber($it)')) @@ -5236,14 +5236,14 @@ separates the autogenerated assertions and the assertion from matchers):

    "/get");
     
     // then:
    - assertThat(response.statusCode()).isEqualTo(200);
    + assertThat(response.statusCode()).isEqualTo(200);
      assertThat(response.header("Content-Type")).matches("application/json.*");
     // and:
      DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
      assertThatJson(parsedJson).field("['valueWithoutAMatcher']").isEqualTo("foo");
     // and:
      assertThat(parsedJson.read("$.duck", String.class)).matches("[0-9]{3}");
    - assertThat(parsedJson.read("$.duck", Integer.class)).isEqualTo(123);
    + assertThat(parsedJson.read("$.duck", Integer.class)).isEqualTo(123);
      assertThat(parsedJson.read("$.alpha", String.class)).matches("[\\p{L}]*");
      assertThat(parsedJson.read("$.alpha", String.class)).isEqualTo("abc");
      assertThat(parsedJson.read("$.number", String.class)).matches("-?(\\d*\\.\\d+|\\d+)");
    @@ -5253,15 +5253,15 @@ separates the autogenerated assertions and the assertion from matchers):

    "$.time", String.class)).matches("(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])");
      assertThat((Object) parsedJson.read("$.valueWithTypeMatch")).isInstanceOf(java.lang.String.class);
      assertThat((Object) parsedJson.read("$.valueWithMin")).isInstanceOf(java.util.List.class);
    - assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMin", java.util.Collection.class)).as("$.valueWithMin").hasSizeGreaterThanOrEqualTo(1);
    + assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMin", java.util.Collection.class)).as("$.valueWithMin").hasSizeGreaterThanOrEqualTo(1);
      assertThat((Object) parsedJson.read("$.valueWithMax")).isInstanceOf(java.util.List.class);
    - assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMax", java.util.Collection.class)).as("$.valueWithMax").hasSizeLessThanOrEqualTo(3);
    + assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMax", java.util.Collection.class)).as("$.valueWithMax").hasSizeLessThanOrEqualTo(3);
      assertThat((Object) parsedJson.read("$.valueWithMinMax")).isInstanceOf(java.util.List.class);
    - assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMinMax", java.util.Collection.class)).as("$.valueWithMinMax").hasSizeBetween(1, 3);
    + assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMinMax", java.util.Collection.class)).as("$.valueWithMinMax").hasSizeBetween(1, 3);
      assertThat((Object) parsedJson.read("$.valueWithMinEmpty")).isInstanceOf(java.util.List.class);
    - assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMinEmpty", java.util.Collection.class)).as("$.valueWithMinEmpty").hasSizeGreaterThanOrEqualTo(0);
    + assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMinEmpty", java.util.Collection.class)).as("$.valueWithMinEmpty").hasSizeGreaterThanOrEqualTo(0);
      assertThat((Object) parsedJson.read("$.valueWithMaxEmpty")).isInstanceOf(java.util.List.class);
    - assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMaxEmpty", java.util.Collection.class)).as("$.valueWithMaxEmpty").hasSizeLessThanOrEqualTo(0);
    + assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMaxEmpty", java.util.Collection.class)).as("$.valueWithMaxEmpty").hasSizeLessThanOrEqualTo(0);
      assertThatValueIsANumber(parsedJson.read("$.duck"));
      assertThat(parsedJson.read("$.['key'].['complex.key']", String.class)).isEqualTo("foo");
    }]},"response" : { - "status" : 200, - "body" : "{\\"date\\":\\"2017-01-01\\",\\"dateTime\\":\\"2017-01-01T01:23:45\\",\\"aBoolean\\":true,\\"valueWithMax\\":[1,2,3],\\"valueWithOccurrence\\":[1,2,3,4],\\"number\\":123,\\"duck\\":123,\\"alpha\\":\\"abc\\",\\"valueWithMin\\":[1,2,3],\\"time\\":\\"01:02:34\\",\\"valueWithTypeMatch\\":\\"string\\",\\"valueWithMinMax\\":[1,2,3],\\"valueWithoutAMatcher\\":\\"foo\\"}", + "status" : 200, + "body" : "{\\"date\\":\\"2017-01-01\\",\\"dateTime\\":\\"2017-01-01T01:23:45\\",\\"aBoolean\\":true,\\"valueWithMax\\":[1,2,3],\\"valueWithOccurrence\\":[1,2,3,4],\\"number\\":123,\\"duck\\":123,\\"alpha\\":\\"abc\\",\\"valueWithMin\\":[1,2,3],\\"time\\":\\"01:02:34\\",\\"valueWithTypeMatch\\":\\"string\\",\\"valueWithMinMax\\":[1,2,3],\\"valueWithoutAMatcher\\":\\"foo\\"}","headers" : {"Content-Type" : "application/json"}, @@ -5386,7 +5386,7 @@ content type set. Otherwise, the default of application/oc String responseAsString = response.readEntity(String.class); // then: - assertThat(response.getStatus()).isEqualTo(200); + assertThat(response.getStatus()).isEqualTo(200); // and: DocumentContext parsedJson = JsonPath.parse(responseAsString); assertThatJson(parsedJson).field("['property1']").isEqualTo("a"); @@ -5414,9 +5414,9 @@ provide an async() method in the '/get' } response { - status 200 + status 200 body 'Passed' - fixedDelayMilliseconds 1000 + fixedDelayMilliseconds 1000 } }

    YAML.  @@ -5454,12 +5454,12 @@ socket.

    Consider the following contract:

    or
     import org.springframework.boot.web.server.LocalServerPort;
     import org.springframework.boot.test.context.SpringBootTest;
     
    -@SpringBootTest(classes = ContextPathTestingBaseClass.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    +@SpringBootTest(classes = ContextPathTestingBaseClass.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
     class ContextPathTestingBaseClass {
     
    -	@LocalServerPort int port;
    +	@LocalServerPort int port;
     
    -	@Before
    +	@Before
     	public void setup() {
     		RestAssured.baseURI = "http://localhost";
     		RestAssured.port = this.port;
    @@ -5486,10 +5486,10 @@ for WebFlux:

    public abstract class BeerRestBase {
     
    -	@Before
    +	@Before
     	public void setup() {
     		RestAssuredWebTestClient.standaloneSetup(
    -		new ProducerController(personToCheck -> personToCheck.age >= 20));
    +		new ProducerController(personToCheck -> personToCheck.age >= 20));
     	}
     }
     }

    8.9.2 WebFlux with Explicit mode

    Another way is with the EXPLICIT mode in your generated tests @@ -5507,25 +5507,25 @@ to work with WebFlux.

    Maven. 

    contracts {
     		testMode = 'EXPLICIT'
     }

    -

    The following example shows how to set up a base class and Rest Assured for Web Flux:

    @RunWith(SpringRunner.class)
    -@SpringBootTest(classes = BeerRestBase.Config.class,
    +

    The following example shows how to set up a base class and Rest Assured for Web Flux:

    @RunWith(SpringRunner.class)
    +@SpringBootTest(classes = BeerRestBase.Config.class,
     		webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
    -		properties = "server.port=0")
    +		properties = "server.port=0")
     public abstract class BeerRestBase {
     
         // your tests go here
     
         // in this config class you define all controllers and mocked services
    -@Configuration
    -@EnableAutoConfiguration
    +@Configuration
    +@EnableAutoConfiguration
     static class Config {
     
    -	@Bean
    +	@Bean
     	PersonCheckingService personCheckingService()  {
    -		return personToCheck -> personToCheck.age >= 20;
    +		return personToCheck -> personToCheck.age >= 20;
     	}
     
    -	@Bean
    +	@Bean
     	ProducerController producerController() {
     		return new ProducerController(personCheckingService());
     	}
    @@ -5551,18 +5551,18 @@ and the appropriate MatchingType as second. All the
     							}
     							body """
     <test>
    -<duck type='xtype'>123</duck>
    +<duck type='xtype'>123</duck>
     <alpha>abc</alpha>
     <list>
     <elem>abc</elem>
     <elem>def</elem>
     <elem>ghi</elem>
     </list>
    -<number>123</number>
    +<number>123</number>
     <aBoolean>true</aBoolean>
    -<date>2017-01-01</date>
    -<dateTime>2017-01-01T01:23:45</dateTime>
    -<time>01:02:34</time>
    +<date>2017-01-01</date>
    +<dateTime>2017-01-01T01:23:45</dateTime>
    +<time>01:02:34</time>
     <valueWithoutAMatcher>foo</valueWithoutAMatcher>
     <key><complex>foo</complex></key>
     </test>"""
    @@ -5581,7 +5581,7 @@ and the appropriate MatchingType as second. All the
     								xPath('/test/duck/@type', byEquality())
     							}
     						}
    -					}

    And below is an example of a YAML contract with XML request and response bodies:

    include::{verifier_core_path}/src/test/resources/yml/contract_rest_xml.yml

    Here is an example of an automatically generated test for XML response body:

    @Test
    +					}

    And below is an example of a YAML contract with XML request and response bodies:

    include::{verifier_core_path}/src/test/resources/yml/contract_rest_xml.yml

    Here is an example of an automatically generated test for XML response body:

    @Test
     public void validate_xmlMatches() throws Exception {
     	// given:
     	MockMvcRequestSpecification request = given()
    @@ -5591,7 +5591,7 @@ and the appropriate MatchingType as second. All the
     	ResponseOptions response = given().spec(request).get("/get");
     
     	// then:
    -	assertThat(response.statusCode()).isEqualTo(200);
    +	assertThat(response.statusCode()).isEqualTo(200);
     	// and:
     	DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance()
     					.newDocumentBuilder();
    @@ -5792,7 +5792,7 @@ leads to generation of two tests that look more or less like this:

    public class V1Test extends TestBase {
     
    -	@Test
    +	@Test
     	public void validate_should_post_a_user() throws Exception {
     		// given:
     			MockMvcRequestSpecification request = given();
    @@ -5802,11 +5802,11 @@ leads to generation of two tests that look more or less like this:

    "/users/1");
     
     		// then:
    -			assertThat(response.statusCode()).isEqualTo(200);
    +			assertThat(response.statusCode()).isEqualTo(200);
     	}
     
    -	@Test
    -	public void validate_withList_1() throws Exception {
    +	@Test
    +	public void validate_withList_1() throws Exception {
     		// given:
     			MockMvcRequestSpecification request = given();
     
    @@ -5815,7 +5815,7 @@ leads to generation of two tests that look more or less like this:

    "/users/2");
     
     		// then:
    -			assertThat(response.statusCode()).isEqualTo(200);
    +			assertThat(response.statusCode()).isEqualTo(200);
     	}
     
     }

    Notice that, for the contract that has the name field, the generated test method is named @@ -5859,22 +5859,22 @@ testCompile 'org import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; -@RunWith(SpringRunner.class) -@SpringBootTest(classes = Application.class) +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Application.class) public abstract class FraudBaseWithWebAppSetup { private static final String OUTPUT = "target/generated-snippets"; - @Rule + @Rule public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(OUTPUT); - @Rule + @Rule public TestName testName = new TestName(); - @Autowired + @Autowired private WebApplicationContext context; - @Before + @Before public void setup() { RestAssuredMockMvc.mockMvc(MockMvcBuilders.webAppContextSetup(this.context) .apply(documentationConfiguration(this.restDocumentation)) @@ -5904,13 +5904,13 @@ testCompile 'org private static final String OUTPUT = "target/generated-snippets"; - @Rule + @Rule public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(OUTPUT); - @Rule + @Rule public TestName testName = new TestName(); - @Before + @Before public void setup() { RestAssuredMockMvc.standaloneSetup(MockMvcBuilders .standaloneSetup(new FraudDetectionController()) @@ -5926,7 +5926,7 @@ maintain the static compatibility. Later in this document, you can see examples import java.util.regex.Pattern; -/** +/** * If you want to use {@link Pattern} directly in your tests * then you can create a class resembling this one. It can * contain all the {@link Pattern} you want to use in the DSL. @@ -5944,7 +5944,7 @@ maintain the static compatibility. Later in this document, you can see examples * and {@code c()} for the consumer side. * * @author Marcin Grzejszczak - */ + */ //tag::impl[] public class PatternUtils { @@ -5960,9 +5960,9 @@ maintain the static compatibility. Later in this document, you can see examples //remove::end[return] } - /** + /** * Makes little sense but it's just an example ;) - */ + */ public static Pattern ok() { //remove::start[] return Pattern.compile("OK"); @@ -5973,7 +5973,7 @@ maintain the static compatibility. Later in this document, you can see examples import org.springframework.cloud.contract.spec.internal.ClientDslProperty; -/** +/** * DSL Properties passed to the DSL from the consumer's perspective. * That means that on the input side {@code Request} for HTTP * or {@code Input} for messaging you can have a regular expression. @@ -5981,10 +5981,10 @@ maintain the static compatibility. Later in this document, you can see examples * you have to have a concrete value. * * @author Marcin Grzejszczak - */ + */ //tag::impl[] public class ConsumerUtils { - /** + /** * Consumer side property. By using the {@link ClientDslProperty} * you can omit most of boilerplate code from the perspective * of dynamic values. Example @@ -6002,13 +6002,13 @@ maintain the static compatibility. Later in this document, you can see examples * and which one to the producer. * * @author Marcin Grzejszczak - */ + */ public static ClientDslProperty oldEnough() { //remove::start[] // this example is not the best one and // theoretically you could just pass the regex instead of `ServerDslProperty` but // it's just to show some new tricks :) - return new ClientDslProperty(PatternUtils.oldEnough(), 40); + return new ClientDslProperty(PatternUtils.oldEnough(), 40); //remove::end[return] } @@ -6017,7 +6017,7 @@ maintain the static compatibility. Later in this document, you can see examples import org.springframework.cloud.contract.spec.internal.ServerDslProperty; -/** +/** * DSL Properties passed to the DSL from the producer's perspective. * That means that on the input side {@code Request} for HTTP * or {@code Input} for messaging you have to have a concrete value. @@ -6025,11 +6025,11 @@ maintain the static compatibility. Later in this document, you can see examples * you can have a regular expression. * * @author Marcin Grzejszczak - */ + */ //tag::impl[] public class ProducerUtils { - /** + /** * Producer side property. By using the {@link ProducerUtils} * you can omit most of boilerplate code from the perspective * of dynamic values. Example @@ -6045,7 +6045,7 @@ maintain the static compatibility. Later in this document, you can see examples * * That way it's in the implementation that we decide what value we will pass to the consumer * and which one to the producer. - */ + */ public static ServerDslProperty ok() { // this example is not the best one and // theoretically you could just pass the regex instead of `ServerDslProperty` but @@ -6123,7 +6123,7 @@ then: } } response { - status 200 + status 200 body(""" { "status": "${value(ProducerUtils.ok())}" @@ -6141,7 +6141,7 @@ can generate tests for other languages) and the way stubs are generated (for exa can generate stubs for other HTTP server implementations).

    10.1 Custom Contract Converter

    The ContractConverter interface lets you register your own implementation of a contract structure converter. The following code listing shows the ContractConverter interface:

    package org.springframework.cloud.contract.spec
     
    -/**
    +/**
      * Converter to be used to convert FROM {@link File} TO {@link Contract}
      * and from {@link Contract} to {@code T}
      *
    @@ -6149,32 +6149,32 @@ structure converter. The following code listing shows the 
      *
      * @author Marcin Grzejszczak
      * @since 1.1.0
    - */
    + */
     interface ContractConverter<T> extends ContractStorer<T> {
     
    -	/**
    +	/**
     	 * Should this file be accepted by the converter. Can use the file extension
     	 * to check if the conversion is possible.
     	 *
     	 * @param file - file to be considered for conversion
     	 * @return - {@code true} if the given implementation can convert the file
    -	 */
    +	 */
     	boolean isAccepted(File file)
     
    -	/**
    +	/**
     	 * Converts the given {@link File} to its {@link Contract} representation
     	 *
     	 * @param file - file to convert
     	 * @return - {@link Contract} representation of the file
    -	 */
    +	 */
     	Collection<Contract> convertFrom(File file)
     
    -	/**
    +	/**
     	 * Converts the given {@link Contract} to a {@link T} representation
     	 *
     	 * @param contract - the parsed contract
     	 * @return - {@link T} the type to which we do the conversion
    -	 */
    +	 */
     	T convertTo(Collection<Contract> contract)
     }

    Your implementation must define the condition on which it should start the conversion. Also, you must define how to perform that conversion in both directions.

    [Important]Important

    Notice that, for the byCommand method, the example calls the assertThatValueIsANumber. This method must be defined in the test base class or be @@ -5318,8 +5318,8 @@ the method name and passed the proper JSON path as a parameter to it.

    [Important]Important

    Once you create your implementation, you must create a @@ -6209,7 +6209,7 @@ set a metaData entry in the Pact file, with key "body": { "clientId": "1234567890", - "loanAmount": 99999 + "loanAmount": 99999 }, "generators": { "body": { @@ -6245,7 +6245,7 @@ set a metaData entry in the Pact file, with key "response": { - "status": 200, + "status": 200, "headers": { "Content-Type": "application/vnd.fraud.v1+json;charset=UTF-8" }, @@ -6310,7 +6310,7 @@ the current Pact version that you use.

    Maven. 

    Gradle. 

    classpath "org.springframework.cloud:spring-cloud-contract-pact:${findProperty('verifierVersion') ?: verifierVersion}"

    When you execute the build of your application, a test will be generated. The generated -test might be as follows:

    @Test
    +test might be as follows:

    @Test
     public void validate_shouldMarkClientAsFraud() throws Exception {
     	// given:
     		MockMvcRequestSpecification request = given()
    @@ -6322,7 +6322,7 @@ test might be as follows:

    "/fraudcheck");
     
     	// then:
    -		assertThat(response.statusCode()).isEqualTo(200);
    +		assertThat(response.statusCode()).isEqualTo(200);
     		assertThat(response.header("Content-Type")).matches("application/vnd\\.fraud\\.v1\\+json.*");
     	// and:
     		DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
    @@ -6347,7 +6347,7 @@ test might be as follows:

    "response" : {
    -    "status" : 200,
    +    "status" : 200,
         "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}",
         "headers" : {
           "Content-Type" : "application/vnd.fraud.v1+json;charset=UTF-8"
    @@ -6372,14 +6372,14 @@ following code listing shows the SingleTestGeneratorimport org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
     import org.springframework.cloud.contract.verifier.file.ContractMetadata
     
    -/**
    +/**
      * Builds a single test.
      *
      * @since 1.1.0
    - */
    + */
     trait SingleTestGenerator {
     
    -	/**
    +	/**
     	 * Creates contents of a single test class in which all test scenarios from
     	 * the contract metadata should be placed.
     	 *
    @@ -6390,12 +6390,12 @@ trait SingleTestGenerator {
     	 * @param includedDirectoryRelativePath - relative path to the included directory
     	 * @return contents of a single test class
     	 * @deprecated use{@link SingleTestGenerator#buildClass(ContractVerifierConfigProperties, Collection, String, GeneratedClassData)}
    -	 */
    -	@Deprecated
    +	 */
    +	@Deprecated
     	abstract String buildClass(ContractVerifierConfigProperties properties,
     			Collection<ContractMetadata> listOfFiles, String className, String classPackage, String includedDirectoryRelativePath)
     
    -	/**
    +	/**
     	 * Creates contents of a single test class in which all test scenarios from
     	 * the contract metadata should be placed.
     	 *
    @@ -6404,7 +6404,7 @@ trait SingleTestGenerator {
     	 * @param generatedClassData - information about the generated class
     	 * @param includedDirectoryRelativePath - relative path to the included directory
     	 * @return contents of a single test class
    -	 */
    +	 */
     	String buildClass(ContractVerifierConfigProperties properties,
     			Collection<ContractMetadata> listOfFiles, String includedDirectoryRelativePath, GeneratedClassData generatedClassData) {
     		String className = generatedClassData.className
    @@ -6413,11 +6413,11 @@ trait SingleTestGenerator {
     		return buildClass(properties, listOfFiles, className, classPackage, path)
     	}
     
    -	/**
    +	/**
     	 * Extension that should be appended to the generated test class. E.g. {@code .java} or {@code .php}
     	 *
     	 * @param properties - properties passed to the plugin
    -	 */
    +	 */
     	abstract String fileExtension(ContractVerifierConfigProperties properties)
     
     	static class GeneratedClassData {
    @@ -6443,26 +6443,26 @@ own implementation of the StubGenerator interface.
     import org.springframework.cloud.contract.spec.Contract
     import org.springframework.cloud.contract.verifier.file.ContractMetadata
     
    -/**
    +/**
      * Converts contracts into their stub representation.
      *
      * @since 1.1.0
    - */
    -@CompileStatic
    + */
    +@CompileStatic
     interface StubGenerator {
     
    -	/**
    +	/**
     	 * @return {@code true} if the converter can handle the file to convert it into a stub.
    -	 */
    +	 */
     	boolean canHandleFileName(String fileName)
     
    -	/**
    +	/**
     	 * @return the collection of converted contracts into stubs. One contract can
     	 * result in multiple stubs.
    -	 */
    +	 */
     	Map<Contract, String> convertContents(String rootName, ContractMetadata content)
     
    -	/**
    +	/**
     	 * @return the name of the converted stub file. If you have multiple contracts
     	 * in a single file then a prefix will be added to the generated file. If you
     	 * provide the {@link Contract#name} field then that field will override the
    @@ -6471,7 +6471,7 @@ own implementation of the StubGenerator interface.
     	 * Example: name of file with 2 contracts is {@code foo.groovy}, it will be
     	 * converted by the implementation to {@code foo.json}. The recursive file
     	 * converter will create two files {@code 0_foo.json} and {@code 1_foo.json}
    -	 */
    +	 */
     	String generateOutputFileNameForInput(String inputFileName)
     }

    Again, you must provide a spring.factories file, such as the one shown in the following example:

    # Stub converters
    @@ -6490,38 +6490,38 @@ HTTP Stub server implementation, which might resemble the following example:

    import org.springframework.cloud.contract.stubrunner.HttpServerStub import org.springframework.util.SocketUtils -@Commons +@Commons class MocoHttpServerStub implements HttpServerStub { private boolean started private JsonRunner runner private int port - @Override + @Override int port() { if (!isRunning()) { - return -1 + return -1 } return port } - @Override + @Override boolean isRunning() { return started } - @Override + @Override HttpServerStub start() { return start(SocketUtils.findAvailableTcpPort()) } - @Override + @Override HttpServerStub start(int port) { this.port = port return this } - @Override + @Override HttpServerStub stop() { if (!isRunning()) { return this @@ -6530,7 +6530,7 @@ HTTP Stub server implementation, which might resemble the following example:

    return this } - @Override + @Override HttpServerStub registerMappings(Collection<File> stubFiles) { List<RunnerSetting> settings = stubFiles.findAll { it.name.endsWith("json") } .collect { @@ -6551,12 +6551,12 @@ HTTP Stub server implementation, which might resemble the following example:

    return this } - @Override + @Override String registeredMappings() { return "" } - @Override + @Override boolean isAccepted(File file) { return file.name.endsWith(".json") } @@ -6568,10 +6568,10 @@ implementation is used. If you provide more than one, the first one on the list class CustomStubDownloaderBuilder implements StubDownloaderBuilder { - @Override + @Override public StubDownloader build(final StubRunnerOptions stubRunnerOptions) { return new StubDownloader() { - @Override + @Override public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar( StubConfiguration config) { File unpackedStubs = retrieveStubs(); @@ -6609,23 +6609,23 @@ the default with spring-boot-starter-web), you can spring-cloud-starter-contract-stub-runner to your classpath and add @AutoConfigureWireMock in order to be able to use Wiremock in your tests. Wiremock runs as a stub server and you can register stub behavior using a Java API or via static JSON declarations as part of -your test. The following code shows an example:

    @RunWith(SpringRunner.class)
    -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
    -@AutoConfigureWireMock(port = 0)
    +your test. The following code shows an example:

    @RunWith(SpringRunner.class)
    +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
    +@AutoConfigureWireMock(port = 0)
     public class WiremockForDocsTests {
     
     	// A service that calls out over HTTP
    -	@Autowired
    +	@Autowired
     	private Service service;
     
    -	@Before
    +	@Before
     	public void setup() {
     		this.service.setBase("http://localhost:"
     				+ this.environment.getProperty("wiremock.server.port"));
     	}
     
     	// Using the WireMock APIs in the normal way:
    -	@Test
    +	@Test
     	public void contextLoads() throws Exception {
     		// Stubbing WireMock
     		stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
    @@ -6659,7 +6659,7 @@ public class WiremockImportApplicationTests {
     }
    [Note]Note

    Actually, WireMock always loads mappings from src/test/resources/mappings as well as the custom locations in the stubs attribute. To change this behavior, you can also specify a files root as described in the next section of this document.

    If you’re using Spring Cloud Contract’s default stub jars, then your -stubs are stored under /META-INF/group-id/artifact-id/versions/mappings/ folder. If you want to register all stubs from that location, from all embedded JARs, then it’s enough to use the following syntax.

    @AutoConfigureWireMock(port = 0, stubs = "classpath*:/META-INF/**/mappings/**/*.json")

    11.2 Using Files to Specify the Stub Bodies

    WireMock can read response bodies from files on the classpath or the file system. In that +stubs are stored under /META-INF/group-id/artifact-id/versions/mappings/ folder. If you want to register all stubs from that location, from all embedded JARs, then it’s enough to use the following syntax.

    @AutoConfigureWireMock(port = 0, stubs = "classpath*:/META-INF/**/mappings/**/*.json")

    11.2 Using Files to Specify the Stub Bodies

    WireMock can read response bodies from files on the classpath or the file system. In that case, you can see in the JSON DSL that the response has a bodyFileName instead of a (literal) body. The files are resolved relative to a root directory (by default, src/test/resources/__files). To customize this location you can set the files @@ -6672,27 +6672,27 @@ automatic loading of stubs, because they come from the root location in a subdirectory called "mappings". The value of files has no effect on the stubs loaded explicitly from the stubs attribute.

    11.3 Alternative: Using JUnit Rules

    For a more conventional WireMock experience, you can use JUnit @Rules to start and stop the server. To do so, use the WireMockSpring convenience class to obtain an Options -instance, as shown in the following example:

    @RunWith(SpringRunner.class)
    -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
    +instance, as shown in the following example:

    @RunWith(SpringRunner.class)
    +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
     public class WiremockForDocsClassRuleTests {
     
     	// Start WireMock on some dynamic port
     	// for some reason `dynamicPort()` is not working properly
    -	@ClassRule
    +	@ClassRule
     	public static WireMockClassRule wiremock = new WireMockClassRule(
     			WireMockSpring.options().dynamicPort());
     
     	// A service that calls out over HTTP to wiremock's port
    -	@Autowired
    +	@Autowired
     	private Service service;
     
    -	@Before
    +	@Before
     	public void setup() {
     		this.service.setBase("http://localhost:" + wiremock.port());
     	}
     
     	// Using the WireMock APIs in the normal way:
    -	@Test
    +	@Test
     	public void contextLoads() throws Exception {
     		// Stubbing WireMock
     		wiremock.stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
    @@ -6708,21 +6708,21 @@ the SSL certificates are not valid (the usual problem with self-installed certif
     The best option is often to re-configure the client to use "http". If that’s not an
     option, you can ask Spring to configure an HTTP client that ignores SSL validation errors
     (do so only for tests, of course).

    To make this work with minimum fuss, you need to be using the Spring Boot -RestTemplateBuilder in your app, as shown in the following example:

    @Bean
    +RestTemplateBuilder in your app, as shown in the following example:

    @Bean
     public RestTemplate restTemplate(RestTemplateBuilder builder) {
     	return builder.build();
     }

    You need RestTemplateBuilder because the builder is passed through callbacks to initialize it, so the SSL validation can be set up in the client at that point. This happens automatically in your test if you are using the @AutoConfigureWireMock annotation or the stub runner. If you use the JUnit @Rule approach, you need to add the -@AutoConfigureHttpClient annotation as well, as shown in the following example:

    @RunWith(SpringRunner.class)
    -@SpringBootTest("app.baseUrl=https://localhost:6443")
    -@AutoConfigureHttpClient
    +@AutoConfigureHttpClient annotation as well, as shown in the following example:

    @RunWith(SpringRunner.class)
    +@SpringBootTest("app.baseUrl=https://localhost:6443")
    +@AutoConfigureHttpClient
     public class WiremockHttpsServerApplicationTests {
     
    -	@ClassRule
    +	@ClassRule
     	public static WireMockClassRule wiremock = new WireMockClassRule(
    -			WireMockSpring.options().httpsPort(6443));
    +			WireMockSpring.options().httpsPort(6443));
     ...
     }

    If you are using spring-boot-starter-test, you have the Apache HTTP client on the classpath and it is selected by the RestTemplateBuilder and configured to ignore SSL @@ -6730,17 +6730,17 @@ errors. If you use the default java.net client, you won’t do any harm). There is no support currently for other clients, but it may be added in future releases.

    To disable the custom RestTemplateBuilder, set the wiremock.rest-template-ssl-enabled property to false.

    11.5 WireMock and Spring MVC Mocks

    Spring Cloud Contract provides a convenience class that can load JSON WireMock stubs into -a Spring MockRestServiceServer. The following code shows an example:

    @RunWith(SpringRunner.class)
    -@SpringBootTest(webEnvironment = WebEnvironment.NONE)
    +a Spring MockRestServiceServer. The following code shows an example:

    @RunWith(SpringRunner.class)
    +@SpringBootTest(webEnvironment = WebEnvironment.NONE)
     public class WiremockForDocsMockServerApplicationTests {
     
    -	@Autowired
    +	@Autowired
     	private RestTemplate restTemplate;
     
    -	@Autowired
    +	@Autowired
     	private Service service;
     
    -	@Test
    +	@Test
     	public void contextLoads() throws Exception {
     		// will read stubs classpath
     		MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate)
    @@ -6763,10 +6763,10 @@ Spring Boot embedded servers, and Wiremock itself has "native" support for a par
     version of Jetty (currently 9.2). To use the native Jetty, you need to add the native
     Wiremock dependencies and exclude the Spring Boot container (if there is one).

    11.6 Customization of WireMock configuration

    You can register a bean of org.springframework.cloud.contract.wiremock.WireMockConfigurationCustomizer type in order to customize the WireMock configuration (e.g. add custom transformers). -Example:

    		@Bean
    +Example:

    		@Bean
     		WireMockConfigurationCustomizer optionsCustomizer() {
     			return new WireMockConfigurationCustomizer() {
    -				@Override
    +				@Override
     				public void customize(WireMockConfiguration options) {
     // perform your customization here
     				}
    @@ -6777,16 +6777,16 @@ or WebTestClient or Rest Assured. At the same time
     generate WireMock stubs by using Spring Cloud Contract WireMock. To do so, write your
     normal REST Docs test cases and use @AutoConfigureRestDocs to have stubs be
     automatically generated in the REST Docs output directory. The following code shows an
    -example using MockMvc:

    @RunWith(SpringRunner.class)
    -@SpringBootTest
    -@AutoConfigureRestDocs(outputDir = "target/snippets")
    -@AutoConfigureMockMvc
    +example using MockMvc:

    @RunWith(SpringRunner.class)
    +@SpringBootTest
    +@AutoConfigureRestDocs(outputDir = "target/snippets")
    +@AutoConfigureMockMvc
     public class ApplicationTests {
     
    -	@Autowired
    +	@Autowired
     	private MockMvc mockMvc;
     
    -	@Test
    +	@Test
     	public void contextLoads() throws Exception {
     		mockMvc.perform(get("/resource"))
     				.andExpect(content().string("Hello World"))
    @@ -6794,16 +6794,16 @@ example using MockMvc:

    WebTestClient (used
    -for testing Spring WebFlux applications) would look like this:

    @RunWith(SpringRunner.class)
    -@SpringBootTest
    -@AutoConfigureRestDocs(outputDir = "target/snippets")
    -@AutoConfigureWebTestClient
    +for testing Spring WebFlux applications) would look like this:

    @RunWith(SpringRunner.class)
    +@SpringBootTest
    +@AutoConfigureRestDocs(outputDir = "target/snippets")
    +@AutoConfigureWebTestClient
     public class ApplicationTests {
     
    -	@Autowired
    +	@Autowired
     	private WebTestClient client;
     
    -	@Test
    +	@Test
     	public void contextLoads() throws Exception {
     		client.get().uri("/resource").exchange()
     				.expectBody(String.class).isEqualTo("Hello World")
    @@ -6837,7 +6837,7 @@ matchers. If JSON Path is unfamiliar, The WebTestClient version of this test
     has a similar verify() static helper that you insert in the same place.

    Instead of the jsonPath and contentType convenience methods, you can also use the WireMock APIs to verify that the request matches the created stub, as shown in the -following example:

    @Test
    +following example:

    @Test
     public void contextLoads() throws Exception {
     	mockMvc.perform(post("/resource")
                    .content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
    @@ -6859,7 +6859,7 @@ range of parameters. The above example generates a stub resembling the following
         }]
       },
       "response" : {
    -    "status" : 200,
    +    "status" : 200,
         "body" : "Hello World",
         "headers" : {
           "X-Application-Context" : "application:-1",
    @@ -6900,7 +6900,7 @@ Contract.make {
             method 'POST'
             url '/foo'
             body('''
    -            {"foo": 23 }
    +            {"foo": 23 }
             ''')
             headers {
                 header('''Accept''', '''application/json''')
    @@ -6926,9 +6926,9 @@ the project’s 

    12.1 1.0.x → 1.1.x

    This section covers upgrading from version 1.0 to version 1.1.

    12.1.1 New structure of generated stubs

    In 1.1.x we have introduced a change to the structure of generated stubs. If you have been using the @AutoConfigureWireMock notation to use the stubs from the classpath, it no longer works. The following example shows how the @AutoConfigureWireMock notation -used to work:

    @AutoConfigureWireMock(stubs = "classpath:/customer-stubs/mappings", port = 8084)

    You must either change the location of the stubs to: +used to work:

    @AutoConfigureWireMock(stubs = "classpath:/customer-stubs/mappings", port = 8084)

    You must either change the location of the stubs to: classpath:…​/META-INF/groupId/artifactId/version/mappings or use the new -classpath-based @AutoConfigureStubRunner, as shown in the following example:

    @AutoConfigureWireMock(stubs = "classpath:customer-stubs/META-INF/travel.components/customer-contract/1.0.2-SNAPSHOT/mappings/", port = 8084)

    If you do not want to use @AutoConfigureStubRunner and you want to remain with the old +classpath-based @AutoConfigureStubRunner, as shown in the following example:

    @AutoConfigureWireMock(stubs = "classpath:customer-stubs/META-INF/travel.components/customer-contract/1.0.2-SNAPSHOT/mappings/", port = 8084)

    If you do not want to use @AutoConfigureStubRunner and you want to remain with the old structure, set your plugin tasks accordingly. The following example would work for the structure presented in the previous snippet.

    Maven. 

    <!-- start of pom.xml -->
    @@ -7011,8 +7011,8 @@ detail.

    TemplateProcessor interface:

    • path()
    • path(int index)

    See issue 388 for more detail.

    12.2.4 RestAssured 3.0

    Rest Assured, used in the generated test classes, got bumped to 3.0. If you manually set versions of Spring Cloud Contract and the release train -you might see the following exception:

    Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile (default-testCompile) on project some-project: Compilation failure: Compilation failure:
    -[ERROR] /some/path/SomeClass.java:[4,39] package com.jayway.restassured.response does not exist

    This exception will occur due to the fact that the tests got generated with +you might see the following exception:

    Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile (default-testCompile) on project some-project: Compilation failure: Compilation failure:
    +[ERROR] /some/path/SomeClass.java:[4,39] package com.jayway.restassured.response does not exist

    This exception will occur due to the fact that the tests got generated with an old version of plugin and at test execution time you have an incompatible version of the release train (and vice versa).

    Done via issue 267

    12.3 1.2.x → 2.0.x

    13. Links

    The following links may be helpful when working with Spring Cloud Contract:

    Summary

    @@ -1773,7 +1773,7 @@ - + @@ -3672,7 +3672,7 @@ - + diff --git a/2.1.x/spring-cloud-contract-maven-plugin/licenses.html b/2.1.x/spring-cloud-contract-maven-plugin/licenses.html index e2d4c22c33..16b1ebb500 100644 --- a/2.1.x/spring-cloud-contract-maven-plugin/licenses.html +++ b/2.1.x/spring-cloud-contract-maven-plugin/licenses.html @@ -332,7 +332,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -340,8 +340,613 @@ implied. See the License for the specific language governing permissions and - limitations under the License.

    -

    Can't read the url [https://www.apache.org/licenses/LICENSE-2.0] : connect timed out

    + limitations under the License.

    [Original text] +

    Copy of the license follows:

    + +
    + +
    + +
    +
    + ApacheCon is Coming 9-12 Sept. 2019 - Las Vegas + The Apache Software Foundation +
    + +
    + Apache Support Logo +
    +
    +
    +

    Apache License, Version 2.0

    + +

    The 2.0 version of the Apache License, approved by the ASF in 2004, helps us achieve our goal of providing +reliable and long-lived software products through collaborative open source software development.

    +

    All packages produced by the ASF are implicitly licensed under the Apache +License, Version 2.0, unless otherwise explicitly stated.

    +
    + +

    +Apache License

    Version 2.0, January 2004

    +http://www.apache.org/licenses/ +

    + +

    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

    + +

    1. Definitions.

    + +
    + +

    "License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document.

    + +

    "Licensor" shall mean the copyright owner or entity authorized by the +copyright owner that is granting the License.

    + +

    "Legal Entity" shall mean the union of the acting entity and all other +entities that control, are controlled by, or are under common control with +that entity. For the purposes of this definition, "control" means (i) the +power, direct or indirect, to cause the direction or management of such +entity, whether by contract or otherwise, or (ii) ownership of fifty +percent (50%) or more of the outstanding shares, or (iii) beneficial +ownership of such entity.

    + +

    "You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License.

    + +

    "Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation source, +and configuration files.

    + +

    "Object" form shall mean any form resulting from mechanical transformation +or translation of a Source form, including but not limited to compiled +object code, generated documentation, and conversions to other media types.

    + +

    "Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice that +is included in or attached to the work (an example is provided in the +Appendix below).

    + +

    "Derivative Works" shall mean any work, whether in Source or Object form, +that is based on (or derived from) the Work and for which the editorial +revisions, annotations, elaborations, or other modifications represent, as +a whole, an original work of authorship. For the purposes of this License, +Derivative Works shall not include works that remain separable from, or +merely link (or bind by name) to the interfaces of, the Work and Derivative +Works thereof.

    + +

    "Contribution" shall mean any work of authorship, including the original +version of the Work and any modifications or additions to that Work or +Derivative Works thereof, that is intentionally submitted to Licensor for +inclusion in the Work by the copyright owner or by an individual or Legal +Entity authorized to submit on behalf of the copyright owner. For the +purposes of this definition, "submitted" means any form of electronic, +verbal, or written communication sent to the Licensor or its +representatives, including but not limited to communication on electronic +mailing lists, source code control systems, and issue tracking systems that +are managed by, or on behalf of, the Licensor for the purpose of discussing +and improving the Work, but excluding communication that is conspicuously +marked or otherwise designated in writing by the copyright owner as "Not a +Contribution."

    + +

    "Contributor" shall mean Licensor and any individual or Legal Entity on +behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work.

    + +
    + +

    2. Grant of Copyright License. Subject to the +terms and conditions of this License, each Contributor hereby grants to You +a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, publicly +display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form.

    + +

    3. Grant of Patent License. Subject to the terms +and conditions of this License, each Contributor hereby grants to You a +perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, use, +offer to sell, sell, import, and otherwise transfer the Work, where such +license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by +combination of their Contribution(s) with the Work to which such +Contribution(s) was submitted. If You institute patent litigation against +any entity (including a cross-claim or counterclaim in a lawsuit) alleging +that the Work or a Contribution incorporated within the Work constitutes +direct or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate as of the +date such litigation is filed.

    + +

    4. Redistribution. You may reproduce and +distribute copies of the Work or Derivative Works thereof in any medium, +with or without modifications, and in Source or Object form, provided that +You meet the following conditions:

    + +
      +
    1. You must give any other recipients of the Work or Derivative Works a +copy of this License; and
    2. + +
    3. You must cause any modified files to carry prominent notices stating +that You changed the files; and
    4. + +
    5. You must retain, in the Source form of any Derivative Works that You +distribute, all copyright, patent, trademark, and attribution notices from +the Source form of the Work, excluding those notices that do not pertain to +any part of the Derivative Works; and
    6. + +
    7. If the Work includes a "NOTICE" text file as part of its distribution, +then any Derivative Works that You distribute must include a readable copy +of the attribution notices contained within such NOTICE file, excluding +those notices that do not pertain to any part of the Derivative Works, in +at least one of the following places: within a NOTICE text file distributed +as part of the Derivative Works; within the Source form or documentation, +if provided along with the Derivative Works; or, within a display generated +by the Derivative Works, if and wherever such third-party notices normally +appear. The contents of the NOTICE file are for informational purposes only +and do not modify the License. You may add Your own attribution notices +within Derivative Works that You distribute, alongside or as an addendum to +the NOTICE text from the Work, provided that such additional attribution +notices cannot be construed as modifying the License. +
      +
      +You may add Your own copyright statement to Your modifications and may +provide additional or different license terms and conditions for use, +reproduction, or distribution of Your modifications, or for any such +Derivative Works as a whole, provided Your use, reproduction, and +distribution of the Work otherwise complies with the conditions stated in +this License. +
    8. + +
    + +

    5. Submission of Contributions. Unless You +explicitly state otherwise, any Contribution intentionally submitted for +inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the +terms of any separate license agreement you may have executed with Licensor +regarding such Contributions.

    + +

    6. Trademarks. This License does not grant +permission to use the trade names, trademarks, service marks, or product +names of the Licensor, except as required for reasonable and customary use +in describing the origin of the Work and reproducing the content of the +NOTICE file.

    + +

    7. Disclaimer of Warranty. Unless required by +applicable law or agreed to in writing, Licensor provides the Work (and +each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, +without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You +are solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise +of permissions under this License.

    + +

    8. Limitation of Liability. In no event and +under no legal theory, whether in tort (including negligence), contract, or +otherwise, unless required by applicable law (such as deliberate and +grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a result +of this License or out of the use or inability to use the Work (including +but not limited to damages for loss of goodwill, work stoppage, computer +failure or malfunction, or any and all other commercial damages or losses), +even if such Contributor has been advised of the possibility of such +damages.

    + +

    9. Accepting Warranty or Additional Liability. +While redistributing the Work or Derivative Works thereof, You may choose +to offer, and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this License. +However, in accepting such obligations, You may act only on Your own behalf +and on Your sole responsibility, not on behalf of any other Contributor, +and only if You agree to indemnify, defend, and hold each Contributor +harmless for any liability incurred by, or claims asserted against, such +Contributor by reason of your accepting any such warranty or additional +liability.

    + +

    END OF TERMS AND CONDITIONS

    + +
    + +

    How to apply the Apache License to your work

    +

    To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included +on the same "printed page" as the copyright notice for easier +identification within third-party archives.

    +
    Copyright [yyyy] [name of copyright owner]
    +
    +Licensed under the Apache License, Version 2.0 (the "License");
    +you may not use this file except in compliance with the License.
    +You may obtain a copy of the License at
    +
    +    http://www.apache.org/licenses/LICENSE-2.0
    +
    +Unless required by applicable law or agreed to in writing, software
    +distributed under the License is distributed on an "AS IS" BASIS,
    +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +See the License for the specific language governing permissions and
    +limitations under the License.
    +
    + + + + + + + + + + + diff --git a/2.1.x/spring-cloud-contract-maven-plugin/plugin-management.html b/2.1.x/spring-cloud-contract-maven-plugin/plugin-management.html index e9d0eb5a2c..0488a35337 100644 --- a/2.1.x/spring-cloud-contract-maven-plugin/plugin-management.html +++ b/2.1.x/spring-cloud-contract-maven-plugin/plugin-management.html @@ -329,7 +329,7 @@ - + @@ -401,7 +401,7 @@ - + diff --git a/2.1.x/spring-cloud-contract-maven-plugin/plugins.html b/2.1.x/spring-cloud-contract-maven-plugin/plugins.html index ddfc401d60..eaff379464 100644 --- a/2.1.x/spring-cloud-contract-maven-plugin/plugins.html +++ b/2.1.x/spring-cloud-contract-maven-plugin/plugins.html @@ -329,7 +329,7 @@ - + diff --git a/2.1.x/spring-cloud-contract.html b/2.1.x/spring-cloud-contract.html index f9f5dcbeb1..5f1edaa2f7 100644 --- a/2.1.x/spring-cloud-contract.html +++ b/2.1.x/spring-cloud-contract.html @@ -5,430 +5,8 @@ -Untitled - - +spring-cloud-contract +
    javadoc JavadocPackage Missing package-info.java file.
    1
     Error sizesjavadoc JavadocPackage Missing package-info.java file.
    1
     Error sizes
    io.spring.javaformat spring-javaformat-maven-plugin0.0.6
    0.0.7
    org.apache.maven.plugins maven-antrun-plugin
    org.springframework.boot spring-boot-maven-plugin2.1.3.RELEASE
    2.1.6.RELEASE
    pl.project13.maven git-commit-id-plugin
    io.spring.javaformat spring-javaformat-maven-plugin0.0.6
    0.0.7
    io.takari.maven.plugins takari-lifecycle-plugin