From e42ea9c343f0959e220e181086872750e5dd04ba Mon Sep 17 00:00:00 2001 From: buildmaster Date: Thu, 25 Jan 2018 16:59:06 +0000 Subject: [PATCH] Sync docs from master to gh-pages --- multi/multi__contract_dsl.html | 716 ++++++-- multi/multi__customization.html | 2 +- multi/multi__spring_cloud_contract_faq.html | 33 +- ...ti__spring_cloud_contract_stub_runner.html | 31 +- ..._cloud_contract_verifier_introduction.html | 148 +- ...ing_cloud_contract_verifier_messaging.html | 52 +- ..._spring_cloud_contract_verifier_setup.html | 78 +- ...multi__spring_cloud_contract_wiremock.html | 52 +- ...lti__using_the_pluggable_architecture.html | 97 +- multi/multi_spring-cloud-contract.html | 2 +- single/spring-cloud-contract.html | 1209 ++++++++++--- .../checkstyle.html | 6 +- .../checkstyle.rss | 4 +- .../complex.html | 6 +- .../configs.html | 6 +- .../convert-mojo.html | 6 +- .../generateStubs-mojo.html | 6 +- .../generateTests-mojo.html | 6 +- .../help-mojo.html | 6 +- spring-cloud-contract-maven-plugin/index.html | 6 +- .../integration.html | 6 +- .../issue-tracking.html | 6 +- spring-cloud-contract-maven-plugin/junit.html | 6 +- .../license.html | 6 +- .../plugin-info.html | 6 +- .../plugin-management.html | 8 +- .../plugins.html | 6 +- .../project-info.html | 6 +- .../project-reports.html | 6 +- .../project-summary.html | 6 +- .../run-mojo.html | 6 +- .../sitemap.html | 6 +- .../source-repository.html | 6 +- spring-cloud-contract-maven-plugin/spock.html | 6 +- .../team-list.html | 6 +- spring-cloud-contract-maven-plugin/usage.html | 6 +- spring-cloud-contract.xml | 1562 ++++++++++++++--- 37 files changed, 3281 insertions(+), 851 deletions(-) diff --git a/multi/multi__contract_dsl.html b/multi/multi__contract_dsl.html index e0a65c04ac..c09e61342f 100644 --- a/multi/multi__contract_dsl.html +++ b/multi/multi__contract_dsl.html @@ -1,15 +1,14 @@ - 8. Contract DSL

8. Contract DSL

[Important]Important

Remember that, inside the contract file, you have to provide the fully + 8. Contract DSL

8. Contract DSL

Spring Cloud Contract supports out of the box 2 types of DSL. One written in +Groovy and one written in YAML.

If you decide to write the contract in Groovy, do not be alarmed if you have not used Groovy +before. Knowledge of the language is not really needed, as the Contract DSL uses only a +tiny subset of it (only literals, method calls and closures). Also, the DSL is statically +typed, to make it programmer-readable without any knowledge of the DSL itself.

[Important]Important

Remember that, inside the Groovy contract file, you have to provide the fully qualified name to the Contract class and make static imports, such as org.springframework.cloud.spec.Contract.make { …​ }. You can also provide an import to the Contract class: import org.springframework.cloud.spec.Contract and then call -Contract.make { …​ }.

Contract DSL is written in Groovy, but do not be alarmed if you have not used Groovy -before. Knowledge of the language is not really needed, as the Contract DSL uses only a -tiny subset of it (only literals, method calls and closures). Also, the DSL is statically -typed, to make it programmer-readable without any knowledge of the DSL itself.

[Tip]Tip

Spring Cloud Contract supports defining multiple contracts in a single file.

The Contract is present in the spring-cloud-contract-spec module of the -Spring -Cloud Contract Verifier repository.

The following is a complete example of a contract definition:

org.springframework.cloud.contract.spec.Contract.make {
+Contract.make { …​ }.

[Tip]Tip

Spring Cloud Contract supports defining multiple contracts in a single file.

The following is a complete example of a Groovy contract definition:

org.springframework.cloud.contract.spec.Contract.make {
 	request {
 		method 'PUT'
 		url '/api/12'
@@ -50,16 +49,60 @@ Cloud Contract Verifier repository.

The following is a complete exampl response { status 200 } -}

[Note]Note

The preceding example does not contain all the features of the DSL appear. The -remainder of this section describes the other features.

You can compile Contracts to WireMock stubs mapping using standalone maven command: -mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:convert

8.1 Limitations

[Warning]Warning

Spring Cloud Contract Verifier does not properly support XML. Please use JSON or +}

The following is a complete example of a YAML contract definition:

description: Some description
+name: some name
+priority: 8
+ignored: true
+request:
+  url: /foo
+  queryParameters:
+    a: b
+    b: c
+  method: PUT
+  headers:
+    foo: bar
+    fooReq: baz
+  body:
+    foo: bar
+  matchers:
+    body:
+      - path: $.foo
+        type: by_regex
+        value: bar
+    headers:
+      - key: foo
+        regex: bar
+response:
+  status: 200
+  headers:
+    foo2: bar
+    foo3: foo33
+    fooRes: baz
+  body:
+    foo2: bar
+    foo3: baz
+  matchers:
+    body:
+      - path: $.foo2
+        type: by_regex
+        value: bar
+      - path: $.foo3
+        type: by_command
+        value: executeMe($it)
+    headers:
+      - key: foo2
+        regex: bar
+      - key: foo3
+        command: andMeToo($it)
[Tip]Tip

You can compile contracts to stubs mapping using standalone maven command: +mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:convert

8.1 Limitations

[Warning]Warning

Spring Cloud Contract Verifier does not properly support XML. Please use JSON or help us implement this feature.

[Warning]Warning

The support for verifying the size of JSON arrays is experimental. If you want to turn it on, please set the value of the following system property to true: spring.cloud.contract.verifier.assert.size. By default, this feature is set to false. You can also provide the assertJsonSize property in the plugin configuration.

[Warning]Warning

Because JSON structure can have any form, it can be impossible to parse it -properly when using the value(consumer(…​), producer(…​)) notation in GString. That +properly when using the Groovy DSL and the value(consumer(…​), producer(…​)) notation in GString. That is why you should use the Groovy Map notation.

8.2 Common Top-Level elements

The following sections describe the most common top-level elements:

8.2.1 Description

You can add a description to your contract. The description is arbitrary text. The -following code shows an example:

		org.springframework.cloud.contract.spec.Contract.make {
+following code shows an example:

Groovy DSL.  +

		org.springframework.cloud.contract.spec.Contract.make {
 			description('''
 given:
 	An input
@@ -68,23 +111,81 @@ when:
 then:
 	Output
 ''')
-		}

8.2.2 Name

You can provide a name for your contract. Assume that you provided the following name: + }

+

YAML.  +

description: Some description
+name: some name
+priority: 8
+ignored: true
+request:
+  url: /foo
+  queryParameters:
+    a: b
+    b: c
+  method: PUT
+  headers:
+    foo: bar
+    fooReq: baz
+  body:
+    foo: bar
+  matchers:
+    body:
+      - path: $.foo
+        type: by_regex
+        value: bar
+    headers:
+      - key: foo
+        regex: bar
+response:
+  status: 200
+  headers:
+    foo2: bar
+    foo3: foo33
+    fooRes: baz
+  body:
+    foo2: bar
+    foo3: baz
+  matchers:
+    body:
+      - path: $.foo2
+        type: by_regex
+        value: bar
+      - path: $.foo3
+        type: by_command
+        value: executeMe($it)
+    headers:
+      - key: foo2
+        regex: bar
+      - key: foo3
+        command: andMeToo($it)

+

8.2.2 Name

You can provide a name for your contract. Assume that you provided the following name: should register a user. If you do so, the name of the autogenerated test is validate_should_register_a_user. Also, the name of the stub in a WireMock stub is should_register_a_user.json.

[Important]Important

You must ensure that the name does not contain any characters that make the generated test not compile. Also, remember that, if you provide the same name for multiple contracts, your autogenerated tests fail to compile and your generated stubs -override each other.

8.2.3 Ignoring Contracts

If you want to ignore a contract, you can either set a value of ignored contracts in the -plugin configuration or set the ignored property on the contract itself:

org.springframework.cloud.contract.spec.Contract.make {
+override each other.

Groovy DSL.  +

org.springframework.cloud.contract.spec.Contract.make {
+	name("some_special_name")
+}

+

YAML.  +

name: some name

+

8.2.3 Ignoring Contracts

If you want to ignore a contract, you can either set a value of ignored contracts in the +plugin configuration or set the ignored property on the contract itself:

Groovy DSL.  +

org.springframework.cloud.contract.spec.Contract.make {
 	ignored()
-}

8.2.4 Passing Values from Files

Starting with version 1.2.0, you can pass values from files. Assume that you have the +}

+

YAML.  +

ignored: true

+

8.2.4 Passing Values from Files

Starting with version 1.2.0, you can pass values from files. Assume that you have the following resources in our project.

└── src
     └── test
         └── resources
             └── contracts
                 ├── readFromFile.groovy
                 ├── request.json
-                └── response.json

Further assume that your contract is as follows:

import org.springframework.cloud.contract.spec.Contract
+                └── response.json

Further assume that your contract is as follows:

Groovy DSL.  +

import org.springframework.cloud.contract.spec.Contract
 
 Contract.make {
 	request {
@@ -102,11 +203,20 @@ Contract.make {
 			contentType(textPlain())
 		}
 	}
-}

Further assume that the JSON files is as follows:

request.json

{ "status" : "REQUEST" }

response.json

{ "status" : "RESPONSE" }

When test or stub generation takes place, the contents of the file is passed to the body -of a request or a response. That works because of the file(…​) method. The argument of -that method needs to be a file with location relative to the folder in which the contract -lays.

8.2.5 HTTP Top-Level Elements

The following methods can be called in the top-level closure of a contract definition. -request and response are mandatory. priority is optional.

org.springframework.cloud.contract.spec.Contract.make {
+}

+

YAML.  +

request:
+  method: GET
+  url: /foo
+  bodyFromFile: request.json
+response:
+  status: 200
+  bodyFromFile: response.json

+

Further assume that the JSON files is as follows:

request.json

{ "status" : "REQUEST" }

response.json

{ "status" : "RESPONSE" }

When test or stub generation takes place, the contents of the file is passed to the body +of a request or a response. The name of the file needs to be a file with location +relative to the folder in which the contract lays.

8.2.5 HTTP Top-Level Elements

The following methods can be called in the top-level closure of a contract definition. +request and response are mandatory. priority is optional.

Groovy DSL.  +

org.springframework.cloud.contract.spec.Contract.make {
 	// Definition of HTTP request part of the contract
 	// (this can be a valid request or invalid depending
 	// on type of contract being specified).
@@ -125,8 +235,18 @@ lays.

// Contract priority, which can be used for overriding // contracts (1 is highest). Priority is optional. priority 1 -}

8.3 Request

The HTTP protocol requires only method and address to be specified in a request. The -same information is mandatory in request definition of the Contract.

org.springframework.cloud.contract.spec.Contract.make {
+}

+

YAML.  +

priority: 8
+request:
+...
+response:
+...

+

[Important]Important

If you want to make your contract have a higher value of priority +you need to pass a lower number to the priority tag / method. E.g. priority with +value 5 has higher priority than priority with value 10.

8.3 Request

The HTTP protocol requires only method and url to be specified in a request. The +same information is mandatory in request definition of the Contract.

Groovy DSL.  +

org.springframework.cloud.contract.spec.Contract.make {
 	request {
 		// HTTP request method (GET/POST/PUT/DELETE).
 		method 'GET'
@@ -138,8 +258,13 @@ same information is mandatory in request definition of the Contract.

//...
 	}
-}

It is possible to specify an absolute rather than relative url, but using urlPath is -the recommended way, as doing so makes the tests host-independent.

org.springframework.cloud.contract.spec.Contract.make {
+}

+

YAML.  +

method: PUT
+url: /foo

+

It is possible to specify an absolute rather than relative url, but using urlPath is +the recommended way, as doing so makes the tests host-independent.

Groovy DSL.  +

org.springframework.cloud.contract.spec.Contract.make {
 	request {
 		method 'GET'
 
@@ -150,8 +275,13 @@ the recommended way, as doing so makes the tests ho
 	response {
 		//...
 	}
-}

request may contain query parameters, which are specified in a closure nested in a -call to urlPath or url.

org.springframework.cloud.contract.spec.Contract.make {
+}

+

YAML.  +

request:
+  method: PUT
+  urlPath: /foo

+

request may contain query parameters.

Groovy DSL.  +

org.springframework.cloud.contract.spec.Contract.make {
 	request {
 		//...
 
@@ -191,7 +321,50 @@ call to urlPath or url
 	response {
 		//...
 	}
-}

request may contain additional request headers, as shown in the following example:

org.springframework.cloud.contract.spec.Contract.make {
+}

+

YAML.  +

request:
+...
+  queryParameters:
+    a: b
+    b: c
+  headers:
+    foo: bar
+    fooReq: baz
+  body:
+    foo: bar
+  matchers:
+    body:
+      - path: $.foo
+        type: by_regex
+        value: bar
+    headers:
+      - key: foo
+        regex: bar
+response:
+  status: 200
+  headers:
+    foo2: bar
+    foo3: foo33
+    fooRes: baz
+  body:
+    foo2: bar
+    foo3: baz
+  matchers:
+    body:
+      - path: $.foo2
+        type: by_regex
+        value: bar
+      - path: $.foo3
+        type: by_command
+        value: executeMe($it)
+    headers:
+      - key: foo2
+        regex: bar
+      - key: foo3
+        command: andMeToo($it)

+

request may contain additional request headers, as shown in the following example:

Groovy DSL.  +

org.springframework.cloud.contract.spec.Contract.make {
 	request {
 		//...
 
@@ -208,7 +381,15 @@ call to urlPath or url
 	response {
 		//...
 	}
-}

request may contain a request body, as shown in the following example:

org.springframework.cloud.contract.spec.Contract.make {
+}

+

YAML.  +

request:
+...
+headers:
+  foo: bar
+  fooReq: baz

+

request may contain a request body:

Groovy DSL.  +

org.springframework.cloud.contract.spec.Contract.make {
 	request {
 		//...
 
@@ -220,8 +401,15 @@ call to urlPath or url
 	response {
 		//...
 	}
-}

request may contain multipart elements. To include multipart elements, call the -multipart() method, as shown in the following example

org.springframework.cloud.contract.spec.Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make {
+}

+

YAML.  +

request:
+...
+body:
+  foo: bar

+

request may contain multipart elements. To include multipart elements, use the +multipart method/section, as shown in the following examples

Groovy DSL.  +

org.springframework.cloud.contract.spec.Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make {
 	request {
 		method "PUT"
 		url "/multipart"
@@ -244,11 +432,49 @@ call to urlPath or url
 	response {
 		status 200
 	}
-}

In the preceding example, we define parameters in either of two ways:

  • Directly, by using the map notation, where the value can be a dynamic property (such as +}

+

YAML.  +

request:
+  method: PUT
+  url: /multipart
+  headers:
+    Content-Type: multipart/form-data;boundary=AaB03x
+  multipart:
+    params:
+    # key (parameter name), value (parameter value) pair
+      formParameter: '"formParameterValue"'
+      someBooleanParameter: true
+    named:
+      - paramName: file
+        fileName: filename.csv
+        fileContent: file content
+  matchers:
+    multipart:
+      params:
+        - key: formParameter
+          regex: ".+"
+        - key: someBooleanParameter
+          predefined: any_boolean
+      named:
+        - paramName: file
+          fileName:
+            predefined: non_empty
+          fileContent:
+            predefined: non_empty
+response:
+  status: 200

+

In the preceding example, we define parameters in either of two ways:

Groovy DSL

  • Directly, by using the map notation, where the value can be a dynamic property (such as formParameter: $(consumer(…​), producer(…​))).
  • By using the named(…​) method that lets you set a named parameter. A named parameter can set a name and content. You can call it either via a method with two arguments, such as named("fileName", "fileContent"), or via a map notation, such as -named(name: "fileName", content: "fileContent").

From this contract, the generated test is as follows:

// given:
+named(name: "fileName", content: "fileContent").

YAML

  • The multipart parameters are set via multipart.params section
  • The named parameters (the fileName and fileContent for a given parameter name) +can be set via the multipart.named section. That section contains +the paramName (name of the parameter), fileName (name of the file), +fileContent (content of the file) fields
  • The dynamic bits can be set via the matchers.multipart section

    • for parameters use the params section that can accept +regex or a predefined regular expression
    • for named params use the named section where first you +define the parameter name via paramName and then you can pass the +parametrization of either fileName or fileContent via +regex or a predefined regular expression

From this contract, the generated test is as follows:

// given:
  MockMvcRequestSpecification request = given()
    .header("Content-Type", "multipart/form-data;boundary=AaB03x")
    .param("formParameter", "\"formParameterValue\"")
@@ -284,7 +510,8 @@ such as named("fileName", "fileContent"), or via a
   }
 }
 	'''

8.4 Response

The response must contain an HTTP status code and may contain other information. The -following code shows an example:

org.springframework.cloud.contract.spec.Contract.make {
+following code shows an example:

Groovy DSL.  +

org.springframework.cloud.contract.spec.Contract.make {
 	request {
 		//...
 	}
@@ -293,12 +520,18 @@ following code shows an example:

org.springframew
 		// in response to request specified above.
 		status 200
 	}
-}

Besides status, the response may contain headers and a body, both of which are +}

+

YAML.  +

response:
+...
+status: 200

+

Besides status, the response may contain headers and a body, both of which are specified the same way as in the request (see the previous paragraph).

8.5 Dynamic properties

The contract can contain some dynamic properties: timestamps, IDs, and so on. You do not want to force the consumers to stub their clocks to always return the same value of time -so that it gets matched by the stub. You can provide the dynamic parts in your contracts +so that it gets matched by the stub.

For Groovy DSL you can provide the dynamic parts in your contracts in two ways: pass them directly in the body or set them in separate sections called -testMatchers and stubMatchers.

8.5.1 Dynamic properties inside the body

You can set the properties inside the body either with the value method or, if you use +testMatchers and stubMatchers.

For YAML you can only use the matchers section.

8.5.1 Dynamic properties inside the body

[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 set the properties inside the body either with the value method or, if you use the Groovy map notation, with $(). The following example shows how to set dynamic properties with the value method:

value(consumer(...), producer(...))
 value(c(...), p(...))
@@ -307,7 +540,8 @@ value(client(...), server(...))

The following example shows how to set d $(c(...), p(...)) $(stub(...), test(...)) $(client(...), server(...))

Both approaches work equally well. stub and client methods are aliases over the consumer -method. Subsequent sections take a closer look at what you can do with those values.

8.5.2 Regular expressions

You can use regular expressions to write your requests in Contract DSL. Doing so is +method. Subsequent sections take a closer look at what you can do with those values.

8.5.2 Regular expressions

[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 use regular expressions to write your requests in Contract DSL. Doing so is particularly useful when you want to indicate that a given response should be provided for requests that follow a given pattern. Also, you can use regular expressions when you 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 {
@@ -453,7 +687,8 @@ Pattern nonBlank() {
 				message: "User not found by email = [${value(producer(regex(email())), consumer('not.existing@user.com'))}]"
 		)
 	}
-}

8.5.3 Passing Optional Parameters

It is possible to provide optional parameters in your contract. However, you can provide +}

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
 	request {
@@ -496,29 +731,30 @@ expression that must be present 0 or more times.

If you use Spock for, the """

The following stub would also be generated:

'''
 {
   "request" : {
-    "url" : "/users/password",
-    "method" : "POST",
-    "bodyPatterns" : [ {
-      "matchesJsonPath" : "$[?(@.['email'] =~ /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,6})?/)]"
-    }, {
-      "matchesJsonPath" : "$[?(@.['callback_url'] =~ /((http[s]?|ftp):\\\\/)\\\\/?([^:\\\\/\\\\s]+)(:[0-9]{1,5})?/)]"
-    } ],
-    "headers" : {
-      "Content-Type" : {
-        "equalTo" : "application/json"
-      }
-    }
+	"url" : "/users/password",
+	"method" : "POST",
+	"bodyPatterns" : [ {
+	  "matchesJsonPath" : "$[?(@.['email'] =~ /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,6})?/)]"
+	}, {
+	  "matchesJsonPath" : "$[?(@.['callback_url'] =~ /((http[s]?|ftp):\\\\/)\\\\/?([^:\\\\/\\\\s]+)(:[0-9]{1,5})?/)]"
+	} ],
+	"headers" : {
+	  "Content-Type" : {
+		"equalTo" : "application/json"
+	  }
+	}
   },
   "response" : {
-    "status" : 404,
-    "body" : "{\\"code\\":\\"123123\\",\\"message\\":\\"User not found by email == [not.existing@user.com]\\"}",
-    "headers" : {
-      "Content-Type" : "application/json"
-    }
+	"status" : 404,
+	"body" : "{\\"code\\":\\"123123\\",\\"message\\":\\"User not found by email == [not.existing@user.com]\\"}",
+	"headers" : {
+	  "Content-Type" : "application/json"
+	}
   },
   "priority" : 1
 }
-'''

8.5.4 Executing Custom Methods on the Server Side

You can define a method call that executes on the server side during the test. Such a +'''

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 method can be added to the class defined as "baseClassForTests" in the configuration. The following code shows an example of the contract portion of the test case:

org.springframework.cloud.contract.spec.Contract.make {
 	request {
@@ -582,11 +818,17 @@ It should resemble the following code:

// 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 -request in your response. To do so, you can use the fromRequest() method, which lets +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 given name.
  • fromRequest().path(): Returns the full path.
  • fromRequest().path(int index): Returns the nth path element.
  • fromRequest().header(String key): Returns the first header with a given name.
  • fromRequest().header(String key, int index): Returns the nth header with a given name.
  • fromRequest().body(): Returns the full request body.
  • fromRequest().body(String jsonPath): Returns the element from the request that -matches the JSON Path.

Consider the following contract:

Contract contractDsl = Contract.make {
+matches the JSON Path.

If you’re using the YAML contract definition you have to use the +Handlebars {{{ }}} notation with custom, Spring Cloud Contract + functions to achieve this.

  • {{{ request.url }}}: Returns the request URL and query parameters.
  • {{{ request.query.key.[index] }}}: Returns the nth query parameter with a given name. +E.g. for key foo, first entry {{{ request.query.foo.[0] }}}
  • {{{ request.path }}}: Returns the full path.
  • {{{ request.path.[index] }}}: Returns the nth path element. E.g. +for first entry `{{{ request.path.[0] }}}
  • {{{ request.headers.key }}}: Returns the first header with a given name.
  • {{{ request.headers.key.[index] }}}: Returns the nth header with a given name.
  • {{{ request.body }}}: Returns the full request body.
  • {{{ jsonpath this 'your.json.path' }}}: Returns the element from the request that +matches the JSON Path. E.g. for json path $.foo - {{{ jsonpath this '$.foo' }}}

Consider the following contract:

Groovy DSL.  +

Contract contractDsl = Contract.make {
 	request {
 		method 'GET'
 		url('/api/v1/xxxx') {
@@ -620,7 +862,39 @@ matches the JSON Path.

Consider the following contract:

"Bla bla ${fromRequest().body('$.foo')} bla bla" ) } -}

Running a JUnit test generation leads to a test that resembles the following example:

// given:
+}

+

YAML.  +

request:
+  method: GET
+  url: /api/v1/xxxx
+  queryParameters:
+    foo:
+      - bar
+      - bar2
+  headers:
+    Authorization:
+      - secret
+      - secret2
+  body:
+    foo: bar
+    baz: 5
+response:
+  status: 200
+  headers:
+    Authorization: "foo {{{ request.headers.Authorization.0 }}} bar"
+  body:
+    url: "{{{ request.url }}}"
+    path: "{{{ request.path }}}"
+    pathIndex: "{{{ request.path.1 }}}"
+    param: "{{{ request.query.foo }}}"
+    paramIndex: "{{{ request.query.foo.1 }}}"
+    authorization: "{{{ request.headers.Authorization.0 }}}"
+    authorization2: "{{{ request.headers.Authorization.1 }}"
+    fullBody: "{{{ request.body }}}"
+    responseFoo: "{{{ jsonpath this '$.foo' }}}"
+    responseBaz: "{{{ jsonpath this '$.baz' }}}"
+    responseBaz2: "Bla bla {{{ jsonpath this '$.foo' }}} bla bla"

+

Running a JUnit test generation leads to a test that resembles the following example:

// given:
  MockMvcRequestSpecification request = given()
    .header("Authorization", "secret")
    .header("Authorization", "secret2")
@@ -723,12 +997,12 @@ org.springframework.cloud.contract.stubrunner.provider.wiremock.TestWireMockExte
 	}
 }

[Important]Important

Remember to override the applyGlobally() method and set it to false if you -want the transformation to be applied only for a mapping that explicitly requires it.

8.5.7 Dynamic Properties in the Matchers Sections

If you work with Pact, the following discussion may seem familiar. +want the transformation to be applied only for a mapping that explicitly requires it.

8.5.7 Dynamic Properties in the Matchers Sections

If you work with Pact, the following discussion may seem familiar. Quite a few users are used to having a separation between the body and setting the dynamic parts of a contract.

You can use two separate sections:

  • stubMatchers, which lets you define the dynamic values that should end up in a stub. You can set it in the request or inputMessage part of your contract.
  • testMatchers, which is present in the response or outputMessage side of the contract.

Currently, Spring Cloud Contract Verifier supports only JSON Path-based matchers with the -following matching possibilities:

  • For stubMatchers:

    • byEquality(): The value taken from the response via the provided JSON Path must be +following matching possibilities:

      Groovy DSL

      • For stubMatchers:

        • byEquality(): The value taken from the response via the provided JSON Path must be equal to the value provided in the contract.
        • byRegex(…​): The value taken from the response via the provided JSON Path must match the regex.
        • byDate(): The value taken from the response via the provided JSON Path must match the regex for an ISO Date value.
        • byTimestamp(): The value taken from the response via the provided JSON Path must @@ -746,7 +1020,15 @@ unflattened collection, use a custom method with the byCom passed as an input to the custom method that you provide. For example, byCommand('foo($it)') results in calling a foo method to which the value matching the JSON Path gets passed. The type of the object read from the JSON can be one of the -following, depending on the JSON path:

          • String: If you point to a String value.
          • JSONArray: If you point to a List.
          • Map: If you point to a Map.
          • Number: If you point to Integer, Double, or other kind of number.
          • Boolean: If you point to a Boolean.

      Consider the following example:

      Contract contractDsl = Contract.make {
      +following, depending on the JSON path:

      • String: If you point to a String value.
      • JSONArray: If you point to a List.
      • Map: If you point to a Map.
      • Number: If you point to Integer, Double, or other kind of number.
      • Boolean: If you point to a Boolean.

YAML. Please read the Groovy section for detailed explanation of +what the types mean

For YAML the structure of a matcher looks like this

- path: $.foo
+  type: by_regex
+  value: bar

Or if you want to use one of the predefined regular expressions +[only_alpha_unicode, number, any_boolean, ip_address, hostname, +email, url, uuid, iso_date, iso_date_time, iso_time, iso_8601_with_offset, non_empty, non_blank]:

- path: $.foo
+  type: by_regex
+  predefined: only_alpha_unicode

Below you can find the allowed list of `type`s.

  • For stubMatchers:

    • by_equality
    • by_regex
    • by_date
    • by_timestamp
    • by_time
  • For testMatchers:

    • by_equality
    • by_regex
    • by_date
    • by_timestamp
    • by_time
    • by_type

      • there are 2 additional fields accepted: minOccurrence and maxOccurrence.
    • by_command

Consider the following example:

Groovy DSL.  +

Contract contractDsl = Contract.make {
 	request {
 		method 'GET'
 		urlPath '/get'
@@ -852,7 +1134,133 @@ following, depending on the JSON path:

    request: + method: GET + urlPath: /get + body: + duck: 123 + alpha: "abc" + number: 123 + aBoolean: true + date: "2017-01-01" + dateTime: "2017-01-01T01:23:45" + time: "01:02:34" + valueWithoutAMatcher: "foo" + valueWithTypeMatch: "string" + key: + "complex.key": 'foo' + matchers: + headers: + - key: Content-Type + regex: "application/json.*" + body: + - path: $.duck + type: by_regex + value: "[0-9]{3}" + - path: $.duck + type: by_equality + - path: $.alpha + type: by_regex + predefined: only_alpha_unicode + - path: $.alpha + type: by_equality + - path: $.number + type: by_regex + predefined: number + - path: $.aBoolean + type: by_regex + predefined: any_boolean + - path: $.date + type: by_date + - path: $.dateTime + type: by_timestamp + - path: $.time + type: by_time + - path: "$.['key'].['complex.key']" + type: by_equality + headers: + Content-Type: application/json +response: + status: 200 + body: + duck: 123 + alpha: "abc" + number: 123 + aBoolean: true + date: "2017-01-01" + dateTime: "2017-01-01T01:23:45" + time: "01:02:34" + valueWithoutAMatcher: "foo" + valueWithTypeMatch: "string" + valueWithMin: + - 1 + - 2 + - 3 + valueWithMax: + - 1 + - 2 + - 3 + valueWithMinMax: + - 1 + - 2 + - 3 + valueWithMinEmpty: [] + valueWithMaxEmpty: [] + key: + 'complex.key' : 'foo' + matchers: + headers: + - key: Content-Type + regex: "application/json.*" + body: + - path: $.duck + type: by_regex + value: "[0-9]{3}" + - path: $.duck + type: by_equality + - path: $.alpha + type: by_regex + predefined: only_alpha_unicode + - path: $.alpha + type: by_equality + - path: $.number + type: by_regex + predefined: number + - path: $.aBoolean + type: by_regex + predefined: any_boolean + - path: $.date + type: by_date + - path: $.dateTime + type: by_timestamp + - path: $.time + type: by_time + - path: $.valueWithTypeMatch + type: by_type + - path: $.valueWithMin + type: by_type + minOccurrence: 1 + - path: $.valueWithMax + type: by_type + maxOccurrence: 3 + - path: $.valueWithMinMax + type: by_type + minOccurrence: 1 + maxOccurrence: 3 + - path: $.valueWithMinEmpty + type: by_type + minOccurrence: 0 + - path: $.valueWithMaxEmpty + type: by_type + maxOccurrence: 0 + - path: $.duck + type: by_command + value: assertThatValueIsANumber($it) + headers: + Content-Type: application/json

+

In the preceding example, you can see the dynamic portions of the contract in the matchers sections. For the request part, you can see that, for all fields but valueWithoutAMatcher, the values of the regular expressions that the stub should contain are explicitly set. For the valueWithoutAMatcher, the verification takes place @@ -908,51 +1316,51 @@ statically imported to your tests. Notice that the byComma the method name and passed the proper JSON path as a parameter to it.

The resulting WireMock stub is in the following example:

				'''
 {
   "request" : {
-    "urlPath" : "/get",
-    "method" : "POST",
-    "headers" : {
-      "Content-Type" : {
-        "matches" : "application/json.*"
-      }
-    },
-    "bodyPatterns" : [ {
-      "matchesJsonPath" : "$[?(@.['valueWithoutAMatcher'] == 'foo')]"
-    }, {
-      "matchesJsonPath" : "$[?(@.['valueWithTypeMatch'] == 'string')]"
-    }, {
-      "matchesJsonPath" : "$.['list'].['some'].['nested'][?(@.['anothervalue'] == 4)]"
-    }, {
-      "matchesJsonPath" : "$.['list'].['someother'].['nested'][?(@.['anothervalue'] == 4)]"
-    }, {
-      "matchesJsonPath" : "$.['list'].['someother'].['nested'][?(@.['json'] == 'with value')]"
-    }, {
-      "matchesJsonPath" : "$[?(@.duck =~ /([0-9]{3})/)]"
-    }, {
-      "matchesJsonPath" : "$[?(@.duck == 123)]"
-    }, {
-      "matchesJsonPath" : "$[?(@.alpha =~ /([\\\\p{L}]*)/)]"
-    }, {
-      "matchesJsonPath" : "$[?(@.alpha == 'abc')]"
-    }, {
-      "matchesJsonPath" : "$[?(@.number =~ /(-?(\\\\d*\\\\.\\\\d+|\\\\d+))/)]"
-    }, {
-      "matchesJsonPath" : "$[?(@.aBoolean =~ /((true|false))/)]"
-    }, {
-      "matchesJsonPath" : "$[?(@.date =~ /((\\\\d\\\\d\\\\d\\\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01]))/)]"
-    }, {
-      "matchesJsonPath" : "$[?(@.dateTime =~ /(([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]))/)]"
-    }, {
-      "matchesJsonPath" : "$[?(@.time =~ /((2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9]))/)]"
-    }, {
-      "matchesJsonPath" : "$.list.some.nested[?(@.json =~ /(.*)/)]"
-    } ]
+	"urlPath" : "/get",
+	"method" : "POST",
+	"headers" : {
+	  "Content-Type" : {
+		"matches" : "application/json.*"
+	  }
+	},
+	"bodyPatterns" : [ {
+	  "matchesJsonPath" : "$[?(@.['valueWithoutAMatcher'] == 'foo')]"
+	}, {
+	  "matchesJsonPath" : "$[?(@.['valueWithTypeMatch'] == 'string')]"
+	}, {
+	  "matchesJsonPath" : "$.['list'].['some'].['nested'][?(@.['anothervalue'] == 4)]"
+	}, {
+	  "matchesJsonPath" : "$.['list'].['someother'].['nested'][?(@.['anothervalue'] == 4)]"
+	}, {
+	  "matchesJsonPath" : "$.['list'].['someother'].['nested'][?(@.['json'] == 'with value')]"
+	}, {
+	  "matchesJsonPath" : "$[?(@.duck =~ /([0-9]{3})/)]"
+	}, {
+	  "matchesJsonPath" : "$[?(@.duck == 123)]"
+	}, {
+	  "matchesJsonPath" : "$[?(@.alpha =~ /([\\\\p{L}]*)/)]"
+	}, {
+	  "matchesJsonPath" : "$[?(@.alpha == 'abc')]"
+	}, {
+	  "matchesJsonPath" : "$[?(@.number =~ /(-?(\\\\d*\\\\.\\\\d+|\\\\d+))/)]"
+	}, {
+	  "matchesJsonPath" : "$[?(@.aBoolean =~ /((true|false))/)]"
+	}, {
+	  "matchesJsonPath" : "$[?(@.date =~ /((\\\\d\\\\d\\\\d\\\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01]))/)]"
+	}, {
+	  "matchesJsonPath" : "$[?(@.dateTime =~ /(([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]))/)]"
+	}, {
+	  "matchesJsonPath" : "$[?(@.time =~ /((2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9]))/)]"
+	}, {
+	  "matchesJsonPath" : "$.list.some.nested[?(@.json =~ /(.*)/)]"
+	} ]
   },
   "response" : {
-    "status" : 200,
-    "body" : "{\\"date\\":\\"2017-01-01\\",\\"dateTime\\":\\"2017-01-01T01:23:45\\",\\"number\\":123,\\"aBoolean\\":true,\\"duck\\":123,\\"alpha\\":\\"abc\\",\\"valueWithMin\\":[1,2,3],\\"time\\":\\"01:02:34\\",\\"valueWithTypeMatch\\":\\"string\\",\\"valueWithMax\\":[1,2,3],\\"valueWithMinMax\\":[1,2,3],\\"valueWithoutAMatcher\\":\\"foo\\"}",
-    "headers" : {
-      "Content-Type" : "application/json"
-    }
+	"status" : 200,
+	"body" : "{\\"date\\":\\"2017-01-01\\",\\"dateTime\\":\\"2017-01-01T01:23:45\\",\\"number\\":123,\\"aBoolean\\":true,\\"duck\\":123,\\"alpha\\":\\"abc\\",\\"valueWithMin\\":[1,2,3],\\"time\\":\\"01:02:34\\",\\"valueWithTypeMatch\\":\\"string\\",\\"valueWithMax\\":[1,2,3],\\"valueWithMinMax\\":[1,2,3],\\"valueWithoutAMatcher\\":\\"foo\\"}",
+	"headers" : {
+	  "Content-Type" : "application/json"
+	}
   }
 }
 '''
[Important]Important

If you use a matcher, then the part of the request aned response that the @@ -1021,7 +1429,8 @@ content type set. Otherwise, the default of application/oc assertThatJson(parsedJson).field("['property1']").isEqualTo("a"); '''

8.7 Async Support

If you’re using asynchronous communication on the server side (your controllers are returning Callable, DeferredResult, and so on), then, inside your contract, you must -provide a sync() method in the response section. The following code shows an example:

org.springframework.cloud.contract.spec.Contract.make {
+provide a sync() method in the response section. The following code shows an example:

Groovy DSL.  +

org.springframework.cloud.contract.spec.Contract.make {
     request {
         method GET()
         url '/get'
@@ -1031,7 +1440,11 @@ provide a sync() method in the 'Passed'
         async()
     }
-}

8.8 Working with Context Paths

Spring Cloud Contract supports context paths.

[Important]Important

The only change needed to fully support context paths is the switch on the +}

+

YAML.  +

response:
+    async: true

+

8.8 Working with Context Paths

Spring Cloud Contract supports context paths.

[Important]Important

The only change needed to fully support context paths is the switch on the PRODUCER side. Also, the autogenerated tests must use EXPLICIT mode. The consumer side remains untouched. In order for the generated test to pass, you must use EXPLICIT mode.

Maven.  @@ -1077,7 +1490,8 @@ socket.

Consider the following contract:

or
 context path included (for example, /my-context-path/url).
  • Your contracts reflect that you have a context path. Your generated stubs also have that information (for example, in the stubs, you have to call /my-context-path/url).
  • 8.9 Messaging Top-Level Elements

    The DSL for messaging looks a little bit different than the one that focuses on HTTP. The following sections explain the differences:

    8.9.1 Output Triggered by a Method

    The output message can be triggered by calling a method (such as a Scheduler when a was -started and a message was sent), as shown in the following example:

    def dsl = Contract.make {
    +started and a message was sent), as shown in the following example:

    Groovy DSL.  +

    def dsl = Contract.make {
     	// Human readable description
     	description 'Some description'
     	// Label by means of which the output message can be triggered
    @@ -1098,11 +1512,31 @@ started and a message was sent), as shown in the following example:

    'BOOK-NAME', 'foo')
     		}
     	}
    -}

    In the previous example case, the output message is sent to output if a method called +}

    +

    YAML.  +

    # Human readable description
    +description: Some description
    +# Label by means of which the output message can be triggered
    +label: some_label
    +input:
    +  # the contract will be triggered by a method
    +  triggeredBy: bookReturnedTriggered()
    +# output message of the contract
    +outputMessage:
    +  # destination to which the output message will be sent
    +  sentTo: output
    +  # the body of the output message
    +  body:
    +    bookName: foo
    +  # the headers of the output message
    +  headers:
    +    BOOK-NAME: foo

    +

    In the previous example case, the output message is sent to output if a method called bookReturnedTriggered is executed. On the message publisher’s side, we generate a test that calls that method to trigger the message. On the consumer side, you can use the some_label to trigger the message.

    8.9.2 Output Triggered by a Message

    The output message can be triggered by receiving a message, as shown in the following -example:

    def dsl = Contract.make {
    +example:

    Groovy DSL.  +

    def dsl = Contract.make {
     	description 'Some Description'
     	label 'some_label'
     	// input is a message
    @@ -1127,11 +1561,36 @@ example:

    def dsl = Contract.make {
     			header('BOOK-NAME', 'foo')
     		}
     	}
    -}

    In the preceding example, the output message is sent to output if a proper message is +}

    +

    YAML.  +

    # Human readable description
    +description: Some description
    +# Label by means of which the output message can be triggered
    +label: some_label
    +# input is a message
    +input:
    +  messageFrom: input
    +  # has the following body
    +  messageBody:
    +    bookName: 'foo'
    +  # and the following headers
    +  messageHeaders:
    +    sample: 'header'
    +# output message of the contract
    +outputMessage:
    +  # destination to which the output message will be sent
    +  sentTo: output
    +  # the body of the output message
    +  body:
    +    bookName: foo
    +  # the headers of the output message
    +  headers:
    +    BOOK-NAME: foo

    +

    In the preceding example, the output message is sent to output if a proper message is received on the input destination. On the message publisher’s side, the engine generates a test that sends the input message to the defined destination. On the consumer side, you can either send a message to the input destination or use a label -(some_label in the example) to trigger the message.

    8.9.3 Consumer/Producer

    In HTTP, you have a notion of client/stub and `server/test notation. You can also +(some_label in the example) to trigger the message.

    8.9.3 Consumer/Producer

    [Important]Important

    This section is valid only for Groovy DSL.

    In HTTP, you have a notion of client/stub and `server/test notation. You can also use those paradigms in messaging. In addition, Spring Cloud Contract Verifier also provides the consumer and producer methods, as presented in the following example (note that you can use either $ or value methods to provide consumer and producer @@ -1152,11 +1611,12 @@ parts):

    Contract.make {
     				bookName: 'foo'
     		])
     	}
    -}

    8.9.4 Common

    In the input {} or outputMessage {} section you can call assertThat with the name +}

    8.9.4 Common

    In the input or outputMessage section you can call assertThat with the name of a method (e.g. assertThatMessageIsOnTheQueue()) that you have defined in the -base class or in a static import. Spring Cloud Pipelines will execute that method -in the genertaed test.

    8.10 Multiple Contracts in One File

    You can define multiple contracts in one file. Such a contract might resemble the -following example:

    import org.springframework.cloud.contract.spec.Contract
    +base class or in a static import. Spring Cloud Contract will execute that method
    +in the generated test.

    8.10 Multiple Contracts in One File

    You can define multiple contracts in one file. Such a contract might resemble the +following example:

    Groovy DSL.  +

    import org.springframework.cloud.contract.spec.Contract
     
     [
             Contract.make {
    @@ -1178,7 +1638,23 @@ following example:

    200
                 }
             }
    -]

    In the preceding example, one contract has the name field and the other does not. This +]

    +

    YAML.  +

    ---
    +name: should post a user
    +request:
    +  method: POST
    +  url: /users/1
    +response:
    +  status: 200
    +
    +---
    +request:
    +  method: POST
    +  url: /users/2
    +response:
    +  status: 200

    +

    In the preceding example, one contract has the name field and the other does not. This leads to generation of two tests that look more or less like this:

    package org.springframework.cloud.contract.verifier.tests.com.hello;
     
     import com.example.TestBase;
    diff --git a/multi/multi__customization.html b/multi/multi__customization.html
    index f193132145..3522c8d4ec 100644
    --- a/multi/multi__customization.html
    +++ b/multi/multi__customization.html
    @@ -1,6 +1,6 @@
     
           
    -   9. Customization

    9. Customization

    You can customize the Spring Cloud Contract Verifier by extending the DSL, as shown in + 9. Customization

    9. Customization

    [Important]Important

    This section is valid only for Groovy DSL

    You can customize the Spring Cloud Contract Verifier by extending the DSL, as shown in the remainder of this section.

    9.1 Extending the DSL

    You can provide your own functions to the DSL. The key requirement for this feature is to maintain the static compatibility. Later in this document, you can see examples of:

    • Creating a JAR with reusable classes.
    • Referencing of these classes in the DSLs.

    You can find the full example here.

    9.1.1 Common JAR

    The following examples show three classes that can be reused in the DSLs.

    PatternUtils contains functions used by both the consumer and the producer.

    package com.example;
    diff --git a/multi/multi__spring_cloud_contract_faq.html b/multi/multi__spring_cloud_contract_faq.html
    index 1aedba9dac..ca450b463f 100644
    --- a/multi/multi__spring_cloud_contract_faq.html
    +++ b/multi/multi__spring_cloud_contract_faq.html
    @@ -2,7 +2,7 @@
           
        3. Spring Cloud Contract FAQ

    3. Spring Cloud Contract FAQ

    3.1 Why use Spring Cloud Contract Verifier and not X ?

    For the time being Spring Cloud Contract Verifier is a JVM based tool. So it could be your first pick when you’re already creating software for the JVM. This project has a lot of really interesting features but especially quite a few of them definitely make -Spring Cloud Contract Verifier stand out on the "market" of Consumer Driven Contract (CDC) tooling. Out of many the most interesting are:

    • Possibility to do CDC with messaging
    • Clear and easy to use, statically typed DSL
    • Possibility to copy paste your current JSON file to the contract and only edit its elements
    • Automatic generation of tests from the defined Contract
    • Stub Runner functionality - the stubs are automatically downloaded at runtime from Nexus / Artifactory
    • Spring Cloud integration - no discovery service is needed for integration tests

    3.2 What is this value(consumer(), producer()) ?

    One of the biggest challenges related to stubs is their reusability. Only if they can be vastly used, will they serve their purpose. +Spring Cloud Contract Verifier stand out on the "market" of Consumer Driven Contract (CDC) tooling. Out of many the most interesting are:

    • Possibility to do CDC with messaging
    • Clear and easy to use, statically typed DSL
    • Possibility to copy paste your current JSON file to the contract and only edit its elements
    • Automatic generation of tests from the defined Contract
    • Stub Runner functionality - the stubs are automatically downloaded at runtime from Nexus / Artifactory
    • Spring Cloud integration - no discovery service is needed for integration tests

    3.2 I don’t want to write a contract in Groovy!

    No problem. You can write a contract in YAML!

    3.3 What is this value(consumer(), producer()) ?

    One of the biggest challenges related to stubs is their reusability. Only if they can be vastly used, will they serve their purpose. What typically makes that difficult are the hard-coded values of request / response elements. For example dates or ids. Imagine the following JSON request

    {
         "time" : "2016-10-10 20:10:15",
    @@ -68,19 +68,19 @@ for time and UUID are simplified and most likely invalid but we want to keep thi
     					])
     			}
     }
    [Important]Important

    Please read the Groovy docs related to JSON to understand how to -properly structure the request / response bodies.

    3.3 How to do Stubs versioning?

    3.3.1 API Versioning

    Let’s try to answer a question what versioning really means. If you’re referring to the API version then there are +properly structure the request / response bodies.

    3.4 How to do Stubs versioning?

    3.4.1 API Versioning

    Let’s try to answer a question what versioning really means. If you’re referring to the API version then there are different approaches.

    • use Hypermedia, links and do not version your API by any means
    • pass versions through headers / urls

    I will not try to answer a question which approach is better. Whatever suit your needs and allows you to generate business value should be picked.

    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 th contract name - whatever suits you more.

    3.3.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 +You can create a subfolder for every version or append it to th 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 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.3.3 Dev or prod stubs

    You can manipulate the classifier to run the tests against current development version of the stubs of other services +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 - once you reach production deployment then you can run tests in one case with dev stubs and one with prod stubs.

    Example of tests using development version of stubs

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

    Example of tests using production version of stubs

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

    You can pass those values also via properties from your deployment pipeline.

    3.4 Common repo with contracts

    Another way of storing contracts other than having them with the producer is keeping them in a common place. + once you reach production deployment then you can run tests in one case with dev stubs and one with prod stubs.

    Example of tests using development version of stubs

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

    Example of tests using production version of stubs

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

    You can pass those values also via properties from your deployment pipeline.

    3.5 Common repo with contracts

    Another way of storing contracts other than having them with the producer is keeping them in a common place. It can be related to security issues where the consumers can’t clone the producer’s code. Also if you keep contracts in a single place then you, as a producer, will know how many consumers you have and which -consumer will you break with your local changes.

    3.4.1 Repo structure

    Let’s assume that we have a producer with coordinates com.example:server and 3 consumers: client1, +consumer will you break with your local changes.

    3.5.1 Repo structure

    Let’s assume that we have a producer with coordinates com.example:server and 3 consumers: client1, client2, client3. Then in the repository with common contracts you would have the following setup (which you can checkout here:

    ├── com
     │   └── example
    @@ -115,7 +115,7 @@ one to one to the contents of the repo.

    Example of a <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> - <version>2.0.0.M6</version> + <version>2.0.0.BUILD-SNAPSHOT</version> <relativePath /> </parent> @@ -271,11 +271,11 @@ Those poms are necessary for the consumer side to run mvn </excludes> </fileSet> </fileSets> -</assembly>

    3.4.2 Workflow

    The workflow would look similar to the one presented in the Step by step guide to CDC. The only difference +</assembly>

    3.5.2 Workflow

    The workflow would look similar to the one presented in the Step by step guide to CDC. The only difference is that the producer doesn’t own the contracts anymore. So the consumer and the producer have to work on - common contracts in a common repository.

    3.4.3 Consumer

    When the consumer wants to work on the contracts offline, instead of cloning the producer code, the + common contracts in a common repository.

    3.5.3 Consumer

    When the consumer wants to work on the contracts offline, instead of cloning the producer code, the consumer team clones the common repository, goes to the required producer’s folder (e.g. com/example/server) -and runs mvn clean install -DskipTests to install locally the stubs converted from the contracts.

    [Tip]Tip

    You need to have Maven installed locally

    3.4.4 Producer

    As a producer it’s enough to alter the Spring Cloud Contract Verifier to provide the URL and the dependency +and runs mvn clean install -DskipTests to install locally the stubs converted from the contracts.

    [Tip]Tip

    You need to have Maven installed locally

    3.5.4 Producer

    As a producer it’s enough to alter the Spring Cloud Contract Verifier to provide the URL and the dependency of the JAR containing the contracts:

    <plugin>
     	<groupId>org.springframework.cloud</groupId>
     	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
    @@ -291,12 +291,13 @@ of the JAR containing the contracts:

    http://link/to/your/nexus/or/artifactory/or/sth. It will be then unpacked in a local temporary folder
     and contracts present under the com/example/server will be picked as the ones used to generate the
     tests and the stubs. Due to this convention the producer team will know which consumer teams will be broken
    -when some incompatible changes are done.

    The rest of the flow looks the same.

    3.5 Can I have multiple base classes for tests?

    Yes! Check out the Different base classes for contracts sections -of either Gradle or Maven plugins.

    3.6 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.6.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 +when some incompatible changes are done.

    The rest of the flow looks the same.

    3.6 Can I have multiple base classes for tests?

    Yes! Check out the Different base classes for contracts sections +of either Gradle or Maven plugins.

    3.7 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.7.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 info and the WireMock notifier to being verbose. Now you will exactly know what request was received by WireMock server and which -matching response definition was picked.

    To turn off this feature just bump WireMock logging to ERROR

    logging.level.com.github.tomakehurst.wiremock=ERROR

    3.6.2 How can I see what got registered in the HTTP server stub?

    You can use the mappingsOutputFolder property on @AutoConfigureStubRunner or StubRunnerRule +matching response definition was picked.

    To turn off this feature just bump WireMock logging to ERROR

    logging.level.com.github.tomakehurst.wiremock=ERROR

    3.7.2 How can I see what got registered in the HTTP server stub?

    You can use the mappingsOutputFolder property on @AutoConfigureStubRunner or StubRunnerRule to dump all mappings per artifact id. Also the port at which the given stub server was -started will be attached.

    3.6.3 Can I reference the request from the response?

    Yes! With version 1.1.0 we’ve added such a possibility. On the HTTP stub server side we’re providing support -for this for WireMock. In case of other HTTP server stubs you’ll have to implement the approach yourself.

    3.6.4 Can I reference text from file?

    Yes! With version 1.2.0 we’ve added such a possibility. It’s enough to call file(…​) method in the -DSL and provide a path relative to where the contract lays.

    \ No newline at end of file +started will be attached.

    3.7.3 Can I reference the request from the response?

    Yes! With version 1.1.0 we’ve added such a possibility. On the HTTP stub server side we’re providing support +for this for WireMock. In case of other HTTP server stubs you’ll have to implement the approach yourself.

    3.7.4 Can I reference text from file?

    Yes! With version 1.2.0 we’ve added such a possibility. It’s enough to call file(…​) method in the +DSL and provide a path relative to where the contract lays. +If you’re using YAML just use the bodyFromFile property.

    \ No newline at end of file diff --git a/multi/multi__spring_cloud_contract_stub_runner.html b/multi/multi__spring_cloud_contract_stub_runner.html index 9077f2ba3b..9c6fca8211 100644 --- a/multi/multi__spring_cloud_contract_stub_runner.html +++ b/multi/multi__spring_cloud_contract_stub_runner.html @@ -89,9 +89,7 @@ it if you want to.

    Maven.  <inherited>false</inherited> <configuration> <attach>true</attach> - <descriptors> - ${basedir}/src/assembly/stub.xml - </descriptors> + <descriptor>${basedir}/src/assembly/stub.xml</descriptor> </configuration> </execution> </executions> @@ -688,4 +686,29 @@ pass an empty classifier this way: groupId:artifactId:vers downloaded.

    port means the port of the WireMock server.

    [Important]Important

    Starting with version 1.0.4, you can provide a range of versions that you would like the Stub Runner to take into consideration. You can read more about the Aether versioning -ranges here.

    \ No newline at end of file +ranges here.

    6.9 Stub Runner Docker

    We’re publishing a spring-cloud/spring-cloud-contract-stub-runner Docker image +that will start the standalone version of Stub Runner.

    If you want to learn more about the basics of Maven, artifact ids, +group ids, classifiers and Artifact Managers, just click here Section 4.5, “Docker Project”.

    6.9.1 How to use it

    Just execute the docker image. You can pass any of the Section 6.8.1, “Common Properties for JUnit and Spring” +as environment variables. The convention is that all the +letters should be upper case. The camel case notation should +and the dot (.) should be separated via underscore (_). E.g. + the stubrunner.repositoryRoot property should be represented + as a STUBRUNNER_REPOSITORY_ROOT environment variable.

    6.9.2 Example of client side usage in a non JVM project

    We’d like to use the stubs created in this Section 4.5.4, “Server side (nodejs)” step. +Let’s assume that we want to run the stubs on port 9876. The NodeJS code +is available here:

    $ git clone https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs
    +$ cd bookstore

    Let’s run the Stub Runner Boot application with the stubs.

    # Provide the Spring Cloud Contract Docker version
    +$ SC_CONTRACT_DOCKER_VERSION="..."
    +# The IP at which the app is running and Docker container can reach it
    +$ APP_IP="192.168.0.100"
    +# Spring Cloud Contract Stub Runner properties
    +$ STUBRUNNER_PORT="8083"
    +# Stub coordinates 'groupId:artifactId:version:classifier:port'
    +$ STUBRUNNER_IDS="com.example:bookstore:0.0.1.RELEASE:stubs:9876"
    +$ STUBRUNNER_REPOSITORY_ROOT="http://${APP_IP}:8081/artifactory/libs-release-local"
    +# Run the docker with Stub Runner Boot
    +$ docker run  --rm -e "STUBRUNNER_IDS=${STUBRUNNER_IDS}" -e "STUBRUNNER_REPOSITORY_ROOT=${STUBRUNNER_REPOSITORY_ROOT}" -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
    +# Now time for the second request
    +$ curl -X GET http://localhost:9876/api/books
    +# You will receive contents of the JSON
    \ No newline at end of file diff --git a/multi/multi__spring_cloud_contract_verifier_introduction.html b/multi/multi__spring_cloud_contract_verifier_introduction.html index 1c320583e3..8bf0237a61 100644 --- a/multi/multi__spring_cloud_contract_verifier_introduction.html +++ b/multi/multi__spring_cloud_contract_verifier_introduction.html @@ -27,7 +27,8 @@ contracts, one for the positive case and one for the negative case. Contract tes used to test contracts between applications and not to simulate full behavior.

    2.3 How It Works

    This section explores how Spring Cloud Contract Verifier with Stub Runner works.

    2.3.1 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.

    package contracts
    +the PUT method.

    Groovy DSL.  +

    package contracts
     
     org.springframework.cloud.contract.spec.Contract.make {
     	request { // (1)
    @@ -83,7 +84,61 @@ From the Producer perspective, in the autogenerated producer-side test:
     (8) - and JSON body equal to
      { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
     (9) - with header `Content-Type` matching `application/json.*`
    - */

    2.3.2 Client Side

    Spring Cloud Contract generates stubs, which you can use during client-side testing. + */

    +

    YAML.  +

    request: # (1)
    +  method: PUT # (2)
    +  url: /fraudcheck # (3)
    +  body: # (4)
    +    "client.id": 1234567890
    +    loanAmount: 99999
    +  headers: # (5)
    +    Content-Type: application/json
    +  matchers:
    +    body:
    +      - path: $.['client.id'] # (6)
    +        type: by_regex
    +        value: "[0-9]{10}"
    +response: # (7)
    +  status: 200 # (8)
    +  body:  # (9)
    +    fraudCheckStatus: "FRAUD"
    +    "rejection.reason": "Amount too high"
    +  headers: # (10)
    +    Content-Type: application/json;charset=UTF-8
    +
    +
    +#From the Consumer perspective, when shooting a request in the integration test:
    +#
    +#(1) - If the consumer sends a request
    +#(2) - With the "PUT" method
    +#(3) - to the URL "/fraudcheck"
    +#(4) - with the JSON body that
    +# * has a field `clientId`
    +# * has a field `loanAmount` that is equal to `99999`
    +#(5) - with header `Content-Type` equal to `application/json`
    +#(6) - and a `client.id` json entry matches the regular expression `[0-9]{10}`
    +#(7) - then the response will be sent with
    +#(8) - status equal `200`
    +#(9) - and JSON body equal to
    +# { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
    +#(10) - with header `Content-Type` equal to `application/json`
    +#
    +#From the Producer perspective, in the autogenerated producer-side test:
    +#
    +#(1) - A request will be sent to the producer
    +#(2) - With the "PUT" method
    +#(3) - to the URL "/fraudcheck"
    +#(4) - with the JSON body that
    +# * has a field `clientId` `1234567890`
    +# * has a field `loanAmount` that is equal to `99999`
    +#(5) - with header `Content-Type` equal to `application/json`
    +#(7) - then the test will assert if the response has been sent with
    +#(8) - status equal `200`
    +#(9) - and JSON body equal to
    +# { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
    +#(10) - with header `Content-Type` equal to `application/json;charset=UTF-8`

    +

    2.3.2 Client Side

    Spring Cloud Contract generates stubs, which you can use during client-side testing. 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,
    @@ -98,7 +153,7 @@ You would like to feed that instance with a proper stub definition.

    At som (or random) port.

    2.3.3 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 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()
    @@ -207,9 +262,10 @@ client wants to borrow. You want to send it to the /fraudc
     				FraudServiceResponse.class);

    For simplicity, the port of the Fraud Detection service is set to 8080, and the application runs on 8090.

    If you start the test at this point, it breaks, because no service currently runs on port 8080.

    Clone the Fraud Detection service repository locally.

    You can start by playing around with the server side contract. To do so, you must first -clone it.

    git clone https://your-git-server.com/server-side.git local-http-server-repo

    Define the contract locally in the repo of Fraud Detection service.

    As a consumer, you need to define what exactly you want to achieve. You need to formulate +clone it.

    $ git clone https://your-git-server.com/server-side.git local-http-server-repo

    Define the contract locally in the repo of Fraud Detection service.

    As a consumer, you need to define what exactly you want to achieve. You need to formulate your expectations. To do so, write the following contract:

    [Important]Important

    Place the contract under src/test/resources/contracts/fraud folder. The fraud folder -is important because the producer’s test base class name references that folder.

    package contracts
    +is important because the producer’s test base class name references that folder.

    Groovy DSL.  +

    package contracts
     
     org.springframework.cloud.contract.spec.Contract.make {
     	request { // (1)
    @@ -265,8 +321,63 @@ From the Producer perspective, in the autogenerated producer-side test:
     (8) - and JSON body equal to
      { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
     (9) - with header `Content-Type` matching `application/json.*`
    - */

    The Contract is written using a statically typed Groovy DSL. You might wonder what about -those value(client(…​), server(…​)) parts. By using this notation, Spring Cloud + */

    +

    YAML.  +

    request: # (1)
    +  method: PUT # (2)
    +  url: /fraudcheck # (3)
    +  body: # (4)
    +    "client.id": 1234567890
    +    loanAmount: 99999
    +  headers: # (5)
    +    Content-Type: application/json
    +  matchers:
    +    body:
    +      - path: $.['client.id'] # (6)
    +        type: by_regex
    +        value: "[0-9]{10}"
    +response: # (7)
    +  status: 200 # (8)
    +  body:  # (9)
    +    fraudCheckStatus: "FRAUD"
    +    "rejection.reason": "Amount too high"
    +  headers: # (10)
    +    Content-Type: application/json;charset=UTF-8
    +
    +
    +#From the Consumer perspective, when shooting a request in the integration test:
    +#
    +#(1) - If the consumer sends a request
    +#(2) - With the "PUT" method
    +#(3) - to the URL "/fraudcheck"
    +#(4) - with the JSON body that
    +# * has a field `clientId`
    +# * has a field `loanAmount` that is equal to `99999`
    +#(5) - with header `Content-Type` equal to `application/json`
    +#(6) - and a `client.id` json entry matches the regular expression `[0-9]{10}`
    +#(7) - then the response will be sent with
    +#(8) - status equal `200`
    +#(9) - and JSON body equal to
    +# { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
    +#(10) - with header `Content-Type` equal to `application/json`
    +#
    +#From the Producer perspective, in the autogenerated producer-side test:
    +#
    +#(1) - A request will be sent to the producer
    +#(2) - With the "PUT" method
    +#(3) - to the URL "/fraudcheck"
    +#(4) - with the JSON body that
    +# * has a field `clientId` `1234567890`
    +# * has a field `loanAmount` that is equal to `99999`
    +#(5) - with header `Content-Type` equal to `application/json`
    +#(7) - then the test will assert if the response has been sent with
    +#(8) - status equal `200`
    +#(9) - and JSON body equal to
    +# { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
    +#(10) - with header `Content-Type` equal to `application/json;charset=UTF-8`

    +

    The YML contract is quite straight-forward. However when you take a look at the Contract +written using a statically typed Groovy DSL - you might wonder what the +value(client(…​), server(…​)) parts are. By using this notation, Spring Cloud Contract lets you define parts of a JSON block, a URL, etc., which are dynamic. In case of an identifier or a timestamp, you need not hardcode a value. You want to allow some different ranges of values. To enable ranges of values, you can set regular expressions @@ -298,8 +409,8 @@ First, add the Spring Cloud Contract BOM.

    </configuration>
     </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 ---
    +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
     [INFO]
     [INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ http-server ---
    @@ -349,8 +460,8 @@ you wish.

    Once you are satisfied with the results and the test passes, pub the server side. Currently, the consumer side work is done.

    2.4.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>
    +}

    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>
     	<groupId>org.springframework.cloud</groupId>
     	<artifactId>spring-cloud-starter-contract-verifier</artifactId>
     	<scope>test</scope>
    @@ -420,8 +531,9 @@ like this:

    "['fraudCheckStatus']").matches("[A-Z]{5}");
             assertThatJson(parsedJson).field("['rejection.reason']").isEqualTo("Amount too high");
    -}

    As you can see, all the producer() parts of the Contract that were present in the -value(consumer(…​), producer(…​)) blocks got injected into the test.

    Note that, on the producer side, you are also doing TDD. The expectations are expressed +}

    If you used the Groovy DSL, you can see, all the producer() parts of the Contract that were present in the +value(consumer(…​), producer(…​)) blocks got injected into the test. +In case of using YAML, the same applied for the matchers sections of the response.

    Note that, on the producer side, you are also doing TDD. The expectations are expressed in the form of a test. This test sends a request to our own application with the URL, 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 @@ -434,11 +546,11 @@ implementation:

    return new FraudCheckResult(FraudCheckStatus.OK, NO_REASON);
     }

    When you execute ./mvnw clean install again, the tests pass. Since the Spring Cloud Contract Verifier plugin adds the tests to the generated-test-sources, you can -actually run those tests from your IDE.

    Deploy your app.

    Once you finish your work, you can deploy your change. First, merge the branch:

    git checkout master
    -git merge --no-ff contract-change-pr
    -git push origin master

    Your CI might run something like ./mvnw clean deploy, which would publish both the -application and the stub artifacts.

    2.4.4 Consumer Side (Loan Issuance) Final Step

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

    Merge branch to master.

    git checkout master
    -git merge --no-ff contract-change-pr

    Work online.

    Now you can disable the offline work for Spring Cloud Contract Stub Runner and indicate +actually run those tests from your IDE.

    Deploy your app.

    Once you finish your work, you can deploy your change. First, merge the branch:

    $ git checkout master
    +$ git merge --no-ff contract-change-pr
    +$ git push origin master

    Your CI might run something like ./mvnw clean deploy, which would publish both the +application and the stub artifacts.

    2.4.4 Consumer Side (Loan Issuance) Final Step

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

    Merge branch to master.

    $ git checkout master
    +$ git merge --no-ff contract-change-pr

    Work online.

    Now you can disable the offline work for Spring Cloud Contract Stub Runner and indicate where the repository with your stubs is located. At this moment the stubs of the server side are automatically downloaded from Nexus/Artifactory. You can set the value of stubsMode to REMOTE. The following code shows an example of diff --git a/multi/multi__spring_cloud_contract_verifier_messaging.html b/multi/multi__spring_cloud_contract_verifier_messaging.html index 0ddf64c23f..b2899fe179 100644 --- a/multi/multi__spring_cloud_contract_verifier_messaging.html +++ b/multi/multi__spring_cloud_contract_verifier_messaging.html @@ -35,7 +35,8 @@ message is triggered by a component inside the application (for example, schedu meanings for different messaging implementations. For Stream and Integration it is first resolved as a destination of a channel. Then, if there is no such destination it is resolved as a channel name. For Camel, that’s a certain component (for example, -jms).

    5.3.1 Scenario 1: No Input Message

    Here is an example for Camel. For the given contract:

    def contractDsl = Contract.make {
    +jms).

    5.3.1 Scenario 1: No Input Message

    Here is an example for Camel. For the given contract:

    Groovy DSL.  +

    def contractDsl = Contract.make {
     	label 'some_label'
     	input {
     		triggeredBy('bookReturnedTriggered()')
    @@ -48,7 +49,19 @@ it is resolved as a channel name. For Camel

    The following JUnit test is created:

    '''
    +}

    +

    YAML.  +

    label: some_label
    +input:
    +  triggeredBy: bookReturnedTriggered
    +outputMessage:
    +  sentTo: activemq:output
    +  body:
    +    bookName: foo
    +  headers:
    +    BOOK-NAME: foo
    +    contentType: application/json

    +

    The following JUnit test is created:

    '''
      // when:
       bookReturnedTriggered();
     
    @@ -75,7 +88,8 @@ it is resolved as a channel name. For Camel"bookName").isEqualTo("foo")
     
    -'''

    5.3.2 Scenario 2: Output Triggered by Input

    Here is an example for Camel. For the given contract:

    def contractDsl = Contract.make {
    +'''

    5.3.2 Scenario 2: Output Triggered by Input

    Here is an example for Camel. For the given contract:

    Groovy DSL.  +

    def contractDsl = Contract.make {
     	label 'some_label'
     	input {
     		messageFrom('jms:input')
    @@ -95,7 +109,22 @@ it is resolved as a channel name. For Camel'BOOK-NAME', 'foo')
     		}
     	}
    -}

    The following JUnit test is created:

    '''
    +}

    +

    YAML.  +

    label: some_label
    +input:
    +  messageFrom: jms:input
    +  messageBody:
    +    bookName: 'foo'
    +  messageHeaders:
    +    sample: header
    +outputMessage:
    +  sentTo: jms:output
    +  body:
    +    bookName: foo
    +  headers:
    +    BOOK-NAME: foo

    +

    The following JUnit test is created:

    '''
     // given:
      ContractVerifierMessage inputMessage = contractVerifierMessaging.create(
       "{\\"bookName\\":\\"foo\\"}"
    @@ -130,7 +159,8 @@ then:
     and:
        DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.payload))
        assertThatJson(parsedJson).field("bookName").isEqualTo("foo")
    -"""

    5.3.3 Scenario 3: No Output Message

    Here is an example for Camel. For the given contract:

    def contractDsl = Contract.make {
    +"""

    5.3.3 Scenario 3: No Output Message

    Here is an example for Camel. For the given contract:

    Groovy DSL.  +

    def contractDsl = Contract.make {
     	label 'some_label'
     	input {
     		messageFrom('jms:delete')
    @@ -142,7 +172,17 @@ and:
     		}
     		assertThat('bookWasDeleted()')
     	}
    -}

    The following JUnit test is created:

    '''
    +}

    +

    YAML.  +

    label: some_label
    +input:
    +  messageFrom: jms:delete
    +  messageBody:
    +    bookName: 'foo'
    +  messageHeaders:
    +    sample: header
    +  assertThat: bookWasDeleted()

    +

    The following JUnit test is created:

    '''
     // given:
      ContractVerifierMessage inputMessage = contractVerifierMessaging.create(
     	"{\\"bookName\\":\\"foo\\"}"
    diff --git a/multi/multi__spring_cloud_contract_verifier_setup.html b/multi/multi__spring_cloud_contract_verifier_setup.html
    index 07167e4d58..3d266193d4 100644
    --- a/multi/multi__spring_cloud_contract_verifier_setup.html
    +++ b/multi/multi__spring_cloud_contract_verifier_setup.html
    @@ -1,6 +1,6 @@
     
           
    -   4. Spring Cloud Contract Verifier Setup

    4. Spring Cloud Contract Verifier Setup

    You can set up Spring Cloud Contract Verifier in either of two ways

    4.1 Gradle Project

    To learn how to set up the Gradle project for Spring Cloud Contract Verifier, read the + 4. Spring Cloud Contract Verifier Setup

    4. Spring Cloud Contract Verifier Setup

    You can set up Spring Cloud Contract Verifier in the following ways:

    4.1 Gradle Project

    To learn how to set up the Gradle project for Spring Cloud Contract Verifier, read the following sections:

    4.1.1 Prerequisites

    In order to use Spring Cloud Contract Verifier with WireMock, you muse use either a Gradle or a Maven plugin.

    [Warning]Warning

    If you want to use Spock in your projects, you must add separately the spock-core and spock-spring modules. Check Spock @@ -552,10 +552,82 @@ optional, they will not get downloaded.

    Creat For example, you might decide to have no dependencies at all.

    Exclude dependencies on the consumer side

    As a consumer, if you add the stub dependency to your classpath, you can explicitly exclude the unwanted dependencies.

    4.4 Scenarios

    You can handle scenarios with Spring Cloud Contract Verifier. All you need to do is to stick to the proper naming convention while creating your contracts. The convention -requires including an order number followed by an underscore, as shown in this example:

    my_contracts_dir\
    +requires including an order number followed by an underscore. This will work regardles
    + of whether you’re working with YAML or Groovy. Example:

    my_contracts_dir\
       scenario1\
         1_login.groovy
         2_showCart.groovy
         3_logout.groovy

    Such a tree causes Spring Cloud Contract Verifier to generate WireMock’s scenario with a name of scenario1 and the three following steps:

    1. login marked as Started pointing to…​
    2. showCart marked as Step1 pointing to…​
    3. logout marked as Step2 which will close the scenario.

    More details about WireMock scenarios can be found at -http://wiremock.org/stateful-behaviour.html

    Spring Cloud Contract Verifier also generates tests with a guaranteed order of execution.

    \ No newline at end of file +http://wiremock.org/stateful-behaviour.html

    Spring Cloud Contract Verifier also generates tests with a guaranteed order of execution.

    4.5 Docker Project

    We’re publishing a springcloud/spring-cloud-contract Docker image +that contains a project that will generate tests and execute them in EXPLICIT mode +against a running application.

    [Tip]Tip

    The EXPLICIT mode means that the tests generated from contracts will send +real requests and not the mocked ones.

    4.5.1 Short intro to Maven, JARs and Binary storage

    Since the Docker image can be used by non JVM projects, it’s good to +explain the basic terms behind Spring Cloud Contract packaging defaults.

    Part of the following definitions were taken from the Maven Glossary

    • Project: Maven thinks in terms of projects. Everything that you +will build are projects. Those projects follow a well defined +“Project Object Model”. Projects can depend on other projects, +in which case the latter are called “dependencies”. A project may +consistent of several subprojects, however these subprojects are still +treated equally as projects.
    • Artifact: An artifact is something that is either produced or used +by a project. Examples of artifacts produced by Maven for a project +include: JARs, source and binary distributions. Each artifact +is uniquely identified by a group id and an artifact ID which is +unique within a group.
    • JAR: JAR stands for Java ARchive. It’s a format based on +the ZIP file format. Spring Cloud Contract packages the contracts and generated +stubs in a JAR file.
    • GroupId: A group ID is a universally unique identifier for a project. +While this is often just the project name (eg. commons-collections), +it is helpful to use a fully-qualified package name to distinguish it +from other projects with a similar name (eg. org.apache.maven). +Typically, when published to the Artifact Manager, the GroupId will get +slash separated and form part of the URL. E.g. for group id com.example +and artifact id application would be /com/example/application/.
    • Classifier: The Maven dependency notation looks as follows: +groupId:artifactId:version:classifier. The classifier is additional suffix +passed to the dependency. E.g. stubs, sources. The same dependency +e.g. com.example:application can produce multiple artifacts that +differ from each other with the classifier.
    • Artifact manager: When you generate binaries / sources / packages, you would +like them to be available for others to download / reference or reuse. In case +of the JVM world those artifacts would be JARs, for Ruby these are gems +and for Docker those would be Docker images. You can store those artifacts +in a manager. Examples of such managers can be Artifactory +or Nexus.

    4.5.2 How it works

    The image searches for contracts under the /contracts folder. +The output from running the tests will be available under +/spring-cloud-contract/build folder (it’s useful for debugging +purposes).

    It’s enough for you to mount your contracts, pass the environment variables + and the image will:

    • generate the contract tests
    • execute the tests against the provided URL
    • generate the WireMock stubs
    • (optional - turned on by default) publish the stubs to a Artifact Manager

    Environment Variables

    The Docker image requires some environment variables to point to +your running application, to the Artifact manager instance etc.

    • PROJECT_GROUP - your project’s group id. Defaults to com.example.
    • PROJECT_VERSION - your project’s version. Defaults to 0.0.1-SNAPSHOT
    • PROJECT_NAME - artifact id. Defaults to example
    • REPO_WITH_BINARIES_URL - URL of your Artifact Manager. Defaults to http://localhost:8081/artifactory/libs-release-local +which is the default URL of Artifactory running locally
    • REPO_WITH_BINARIES_USERNAME - (optional) username when the Artifact Manager is secured
    • REPO_WITH_BINARIES_PASSWORD - (optional) password when the Artifact Manager is secured
    • PUBLISH_ARTIFACTS - if set to true then will publish artifact to binary storage. Defaults to true.

    These environment variables are used when tests are executed:

    • APPLICATION_BASE_URL - url against which tests should be executed. +Remember that it has to be accessible from the Docker container (e.g. localhost +will not work)
    • APPLICATION_USERNAME - (optional) username for basic authentication to your application
    • APPLICATION_PASSWORD - (optional) password for basic authentication to your application

    4.5.3 Example of usage

    Let’s take a look at a simple MVC application

    $ git clone https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs
    +$ cd bookstore

    The contracts are available under /contracts folder.

    4.5.4 Server side (nodejs)

    Since we want to run tests, we could just execute:

    $ npm test

    however, for learning purposes, let’s split it into pieces:

    # Stop docker infra (nodejs, artifactory)
    +$ ./stop_infra.sh
    +# Start docker infra (nodejs, artifactory)
    +$ ./setup_infra.sh
    +
    +# Kill & Run app
    +$ pkill -f "node app"
    +$ nohup node app &
    +
    +# Prepare environment variables
    +$ SC_CONTRACT_DOCKER_VERSION="..."
    +$ APP_IP="192.168.0.100"
    +$ APP_PORT="3000"
    +$ ARTIFACTORY_PORT="8081"
    +$ APPLICATION_BASE_URL="http://${APP_IP}:${APP_PORT}"
    +$ ARTIFACTORY_URL="http://${APP_IP}:${ARTIFACTORY_PORT}/artifactory/libs-release-local"
    +$ CURRENT_DIR="$( pwd )"
    +$ CURRENT_FOLDER_NAME=${PWD##*/}
    +$ PROJECT_VERSION="0.0.1.RELEASE"
    +
    +# Execute contract tests
    +$ docker run  --rm -e "APPLICATION_BASE_URL=${APPLICATION_BASE_URL}" -e "PUBLISH_ARTIFACTS=true" -e "PROJECT_NAME=${CURRENT_FOLDER_NAME}" -e "REPO_WITH_BINARIES_URL=${ARTIFACTORY_URL}" -e "PROJECT_VERSION=${PROJECT_VERSION}" -v "${CURRENT_DIR}/contracts/:/contracts:ro" -v "${CURRENT_DIR}/node_modules/spring-cloud-contract/output:/spring-cloud-contract-output/" springcloud/spring-cloud-contract:"${SC_CONTRACT_DOCKER_VERSION}"
    +
    +# Kill app
    +$ pkill -f "node app"

    What will happen is that via bash scripts:

    • infrastructure will be set up (MongoDb, Artifactory). +In real life scenario you would just run the NodeJS application +with mocked database. In this example we want to show how we can +benefit from Spring Cloud Contract in no time.
    • due to those constraints the contracts also represent the +stateful situation

      • first request is a POST that causes data to get inserted to the database
      • second request is a GET that returns a list of data with 1 previously inserted element
    • the NodeJS application will be started (on port 3000)
    • contract tests will be generated via Docker and tests +will be executed against the running application

      • the contracts will be taken from /contracts folder.
      • the output of the test execution is available under +node_modules/spring-cloud-contract/output.
    • the stubs will be uploaded to Artifactory. You can check them out +under http://localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/ . +The stubs will be here http://localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/bookstore-0.0.1.RELEASE-stubs.jar.

    To see how the client side looks like check out the Section 6.9, “Stub Runner Docker” section.

    \ No newline at end of file diff --git a/multi/multi__spring_cloud_contract_wiremock.html b/multi/multi__spring_cloud_contract_wiremock.html index 4ede2d2731..816fc79850 100644 --- a/multi/multi__spring_cloud_contract_wiremock.html +++ b/multi/multi__spring_cloud_contract_wiremock.html @@ -152,12 +152,13 @@ Example:

    		

    11.7 Generating Stubs using REST Docs

    Spring REST Docs can be used to generate -documentation (for example in Asciidoctor format) for an HTTP API with Spring MockMvc or +documentation (for example in Asciidoctor format) for an HTTP API with Spring MockMvc +or WebTestClient or Rest Assured. At the same time that you generate documentation for your API, you can also generate WireMock stubs by using Spring Cloud Contract WireMock. To do so, write your normal REST Docs test cases and use @AutoConfigureRestDocs to have stubs be automatically generated in the REST Docs output directory. The following code shows an -example:

    @RunWith(SpringRunner.class)
    +example using MockMvc:

    @RunWith(SpringRunner.class)
     @SpringBootTest
     @AutoConfigureRestDocs(outputDir = "target/snippets")
     @AutoConfigureMockMvc
    @@ -173,32 +174,49 @@ example:

    "resource"));
     	}
     }

    This test generates a WireMock stub at "target/snippets/stubs/resource.json". It matches -all GET requests to the "/resource" path.

    Without any additional configuration, this tests creates a stub with a request matcher +all GET requests to the "/resource" path. The same example with WebTestClient (used +for testing Spring WebFlux applications) would look like this:

    @RunWith(SpringRunner.class)
    +@SpringBootTest
    +@AutoConfigureRestDocs(outputDir = "target/snippets")
    +@AutoConfigureWebTestClient
    +public class ApplicationTests {
    +
    +	@Autowired
    +	private WebTestClient client;
    +
    +	@Test
    +	public void contextLoads() throws Exception {
    +		client.get().uri("/resource").exchange()
    +				.expectBody(String.class).isEqualTo("Hello World")
    + 				.consumeWith(document("resource"));
    +	}
    +}

    Without any additional configuration, these tests create a stub with a request matcher for the HTTP method and all headers except "host" and "content-length". To match the request more precisely (for example, to match the body of a POST or PUT), we need to explicitly create a request matcher. Doing so has two effects:

    • Creating a stub that matches only in the way you specify.
    • Asserting that the request in the test case also matches the same conditions.

    The main entry point for this feature is WireMockRestDocs.verify(), which can be used as a substitute for the document() convenience method, as shown in the following -example:

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

    import static org.springframework.cloud.contract.wiremock.restdocs.WireMockRestDocs.verify;
    @RunWith(SpringRunner.class)
    +@SpringBootTest
    +@AutoConfigureRestDocs(outputDir = "target/snippets")
    +@AutoConfigureMockMvc
    +public class ApplicationTests {
     
    -	@Autowired
    -	private MockMvc mockMvc;
    +	@Autowired
    +	private MockMvc mockMvc;
     
    -	@Test
    -	public void contextLoads() throws Exception {
    -		mockMvc.perform(post("/resource")
    -                .content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
    +	@Test
    +	public void contextLoads() throws Exception {
    +		mockMvc.perform(post("/resource")
    +                .content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
     				.andExpect(status().isOk())
    -				.andDo(verify().jsonPath("$.id")
    -                        .stub("resource"));
    +				.andDo(verify().jsonPath("$.id")
    +                        .stub("resource"));
     	}
     }

    This contract specifies that any valid POST with an "id" field receives the response defined in this test. You can chain together calls to .jsonPath() to add additional matchers. If JSON Path is unfamiliar, The JayWay -documentation can help you get up to speed.

    Instead of the jsonPath and contentType convenience methods, you can also use the +documentation can help you get up to speed. 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
     public void contextLoads() throws Exception {
    diff --git a/multi/multi__using_the_pluggable_architecture.html b/multi/multi__using_the_pluggable_architecture.html
    index e3d592ed0b..7fdb9e97bd 100644
    --- a/multi/multi__using_the_pluggable_architecture.html
    +++ b/multi/multi__using_the_pluggable_architecture.html
    @@ -5,19 +5,7 @@ such as YAML, RAML or PACT. In those cases, you still want to benefit from the a
     generation of tests and stubs. You can add your own implementation for generating both
     tests and stubs. Also, you can customize the way tests are generated (for example, you
     can generate tests for other languages) and the way stubs are generated (for example, you
    -can generate stubs for other HTTP server implementations).

    10.1 Custom Contract Converter

    Assume that your contract is written in a YAML file as follows:

    request:
    -  url: /foo
    -  method: PUT
    -  headers:
    -    foo: bar
    -  body:
    -    foo: bar
    -response:
    -  status: 200
    -  headers:
    -    foo2: bar
    -  body:
    -    foo2: bar

    The ContractConverter interface lets you register your own implementation of a contract +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
     
     /**
    @@ -58,87 +46,8 @@ structure converter. The following code listing shows the 
     }

    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 /META-INF/spring.factories file in which you provide the fully qualified name of your -implementation.

    The following example shows a typical spring.factories file:

    # Converters
    -org.springframework.cloud.contract.spec.ContractConverter=\
    -org.springframework.cloud.contract.verifier.converter.YamlContractConverter
    -
    -# tag::extension[]
    -org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockExtensions=\
    -org.springframework.cloud.contract.verifier.dsl.wiremock.TestWireMockExtensions
    -# end::extension[]

    The following example shows a typical YAML implementation that matches the preceding -example:

    package org.springframework.cloud.contract.verifier.converter
    -
    -import java.nio.file.Files
    -
    -import groovy.transform.CompileStatic
    -import org.springframework.cloud.contract.spec.Contract
    -import org.springframework.cloud.contract.spec.ContractConverter
    -import org.springframework.cloud.contract.spec.internal.Headers
    -import org.yaml.snakeyaml.Yaml
    -
    -/**
    - * Simple converter from and to a {@link YamlContract} to a collection of {@link Contract}
    - */
    -@CompileStatic
    -class YamlContractConverter implements ContractConverter<List<YamlContract>> {
    -
    -	@Override
    -	public boolean isAccepted(File file) {
    -		String name = file.getName()
    -		return name.endsWith(".yml") || name.endsWith(".yaml")
    -	}
    -
    -	@Override
    -	public Collection<Contract> convertFrom(File file) {
    -		try {
    -			YamlContract yamlContract = new Yaml().loadAs(
    -					Files.newInputStream(file.toPath()), YamlContract.class)
    -			return [Contract.make {
    -				request {
    -					method(yamlContract?.request?.method)
    -					url(yamlContract?.request?.url)
    -					headers {
    -						yamlContract?.request?.headers?.each { String key, Object value ->
    -							header(key, value)
    -						}
    -					}
    -					body(yamlContract?.request?.body)
    -				}
    -				response {
    -					status(yamlContract?.response?.status)
    -					headers {
    -						yamlContract?.response?.headers?.each { String key, Object value ->
    -							header(key, value)
    -						}
    -					}
    -					body(yamlContract?.response?.body)
    -				}
    -			}]
    -		}
    -		catch (FileNotFoundException e) {
    -			throw new IllegalStateException(e)
    -		}
    -	}
    -
    -	@Override
    -	public List<YamlContract> convertTo(Collection<Contract> contracts) {
    -		return contracts.collect { Contract contract ->
    -			YamlContract yamlContract = new YamlContract()
    -			yamlContract.request.with {
    -				method = contract?.request?.method?.clientValue
    -				url = contract?.request?.url?.clientValue
    -				headers = (contract?.request?.headers as Headers)?.asStubSideMap()
    -				body = contract?.request?.body?.clientValue as Map
    -			}
    -			yamlContract.response.with {
    -				status = contract?.response?.status?.clientValue as Integer
    -				headers = (contract?.response?.headers as Headers)?.asStubSideMap()
    -				body = contract?.response?.body?.clientValue as Map
    -			}
    -			return yamlContract
    -		}
    -	}
    -}

    10.1.1 Pact Converter

    Spring Cloud Contract includes support for Pact representation of +implementation.

    The following example shows a typical spring.factories file:

    org.springframework.cloud.contract.spec.ContractConverter=\
    +org.springframework.cloud.contract.verifier.converter.YamlContractConverter

    10.1.1 Pact Converter

    Spring Cloud Contract includes support for Pact representation of contracts. Instead of using the Groovy DSL, you can use Pact files. In this section, we present how to add Pact support for your project.

    10.1.2 Pact Contract

    Consider following example of a Pact contract, which is a file under the src/test/resources/contracts folder.

    {
    diff --git a/multi/multi_spring-cloud-contract.html b/multi/multi_spring-cloud-contract.html
    index 1198d9ea04..80063b220c 100644
    --- a/multi/multi_spring-cloud-contract.html
    +++ b/multi/multi_spring-cloud-contract.html
    @@ -1,3 +1,3 @@
     
           
    -   Spring Cloud Contract

    Spring Cloud Contract


    Table of Contents

    1. Spring Cloud Contract
    2. Spring Cloud Contract Verifier Introduction
    2.1. Why a Contract Verifier?
    2.1.1. Testing issues
    2.2. Purposes
    2.3. How It Works
    2.3.1. Defining the contract
    2.3.2. Client Side
    2.3.3. Server Side
    2.4. Step-by-step Guide to Consumer Driven Contracts (CDC)
    2.4.1. Technical note
    2.4.2. Consumer side (Loan Issuance)
    2.4.3. Producer side (Fraud Detection server)
    2.4.4. Consumer Side (Loan Issuance) Final Step
    2.5. Dependencies
    2.6. Additional Links
    2.6.1. Spring Cloud Contract video
    2.6.2. Readings
    2.7. Samples
    3. Spring Cloud Contract FAQ
    3.1. Why use Spring Cloud Contract Verifier and not X ?
    3.2. What is this value(consumer(), producer()) ?
    3.3. How to do Stubs versioning?
    3.3.1. API Versioning
    3.3.2. JAR versioning
    3.3.3. Dev or prod stubs
    3.4. Common repo with contracts
    3.4.1. Repo structure
    3.4.2. Workflow
    3.4.3. Consumer
    3.4.4. Producer
    3.5. Can I have multiple base classes for tests?
    3.6. How can I debug the request/response being sent by the generated tests client?
    3.6.1. How can I debug the mapping/request/response being sent by WireMock?
    3.6.2. How can I see what got registered in the HTTP server stub?
    3.6.3. Can I reference the request from the response?
    3.6.4. Can I reference text from file?
    4. Spring Cloud Contract Verifier Setup
    4.1. Gradle Project
    4.1.1. Prerequisites
    4.1.2. Add Gradle Plugin with Dependencies
    4.1.3. Gradle and Rest Assured 2.0
    4.1.4. Snapshot Versions for Gradle
    4.1.5. Add stubs
    4.1.6. Run the Plugin
    4.1.7. Default Setup
    4.1.8. Configure Plugin
    4.1.9. Configuration Options
    4.1.10. Single Base Class for All Tests
    4.1.11. Different Base Classes for Contracts
    4.1.12. Invoking Generated Tests
    4.1.13. Spring Cloud Contract Verifier on the Consumer Side
    4.2. Maven Project
    4.2.1. Add maven plugin
    4.2.2. Maven and Rest Assured 2.0
    4.2.3. Snapshot versions for Maven
    4.2.4. Add stubs
    4.2.5. Run plugin
    4.2.6. Configure plugin
    4.2.7. Configuration Options
    4.2.8. Single Base Class for All Tests
    4.2.9. Different base classes for contracts
    4.2.10. Invoking generated tests
    4.2.11. Maven Plugin and STS
    4.2.12. Spring Cloud Contract Verifier on the Consumer Side
    4.3. Stubs and Transitive Dependencies
    4.4. Scenarios
    5. Spring Cloud Contract Verifier Messaging
    5.1. Integrations
    5.2. Manual Integration Testing
    5.3. Publisher-Side Test Generation
    5.3.1. Scenario 1: No Input Message
    5.3.2. Scenario 2: Output Triggered by Input
    5.3.3. Scenario 3: No Output Message
    5.4. Consumer Stub Generation
    6. Spring Cloud Contract Stub Runner
    6.1. Snapshot versions
    6.2. Publishing Stubs as JARs
    6.3. Stub Runner Core
    6.3.1. Retrieving stubs
    Stub downloading
    Classpath scanning
    6.3.2. Running stubs
    Limitations
    Running using main app
    HTTP Stubs
    Viewing registered mappings
    Messaging Stubs
    6.4. Stub Runner JUnit Rule
    6.4.1. Maven settings
    6.4.2. Providing fixed ports
    6.4.3. Fluent API
    6.4.4. Stub Runner with Spring
    6.5. Stub Runner Spring Cloud
    6.5.1. Stubbing Service Discovery
    Test profiles and service discovery
    6.5.2. Additional Configuration
    6.6. Stub Runner Boot Application
    6.6.1. How to use it?
    Stub Runner Server
    Spring Cloud CLI
    6.6.2. Endpoints
    HTTP
    Messaging
    6.6.3. Example
    6.6.4. Stub Runner Boot with Service Discovery
    6.7. Stubs Per Consumer
    6.8. Common
    6.8.1. Common Properties for JUnit and Spring
    6.8.2. Stub Runner Stubs IDs
    7. Stub Runner for Messaging
    7.1. Stub triggering
    7.1.1. Trigger by Label
    7.1.2. Trigger by Group and Artifact Ids
    7.1.3. Trigger by Artifact Ids
    7.1.4. Trigger All Messages
    7.2. Stub Runner Integration
    7.2.1. Adding the Runner to the Project
    7.2.2. Disabling the functionality
    Scenario 1 (no input message)
    Scenario 2 (output triggered by input)
    Scenario 3 (input with no output)
    7.3. Stub Runner Stream
    7.3.1. Adding the Runner to the Project
    7.3.2. Disabling the functionality
    Scenario 1 (no input message)
    Scenario 2 (output triggered by input)
    Scenario 3 (input with no output)
    7.4. Stub Runner Spring AMQP
    7.4.1. Adding the Runner to the Project
    Triggering the message
    Spring AMQP Test Configuration
    8. Contract DSL
    8.1. Limitations
    8.2. Common Top-Level elements
    8.2.1. Description
    8.2.2. Name
    8.2.3. Ignoring Contracts
    8.2.4. Passing Values from Files
    8.2.5. HTTP Top-Level Elements
    8.3. Request
    8.4. Response
    8.5. Dynamic properties
    8.5.1. Dynamic properties inside the body
    8.5.2. Regular expressions
    8.5.3. Passing Optional Parameters
    8.5.4. Executing Custom Methods on the Server Side
    8.5.5. Referencing the Request from the Response
    8.5.6. Registering Your Own WireMock Extension
    8.5.7. Dynamic Properties in the Matchers Sections
    8.6. JAX-RS Support
    8.7. Async Support
    8.8. Working with Context Paths
    8.9. Messaging Top-Level Elements
    8.9.1. Output Triggered by a Method
    8.9.2. Output Triggered by a Message
    8.9.3. Consumer/Producer
    8.9.4. Common
    8.10. Multiple Contracts in One File
    9. Customization
    9.1. Extending the DSL
    9.1.1. Common JAR
    9.1.2. Adding the Dependency to the Project
    9.1.3. Test the Dependency in the Project’s Dependencies
    9.1.4. Test a Dependency in the Plugin’s Dependencies
    9.1.5. Referencing classes in DSLs
    10. Using the Pluggable Architecture
    10.1. Custom Contract Converter
    10.1.1. Pact Converter
    10.1.2. Pact Contract
    10.1.3. Pact for Producers
    10.1.4. Pact for Consumers
    10.2. Using the Custom Test Generator
    10.3. Using the Custom Stub Generator
    10.4. Using the Custom Stub Runner
    10.5. Using the Custom Stub Downloader
    11. Spring Cloud Contract WireMock
    11.1. Registering Stubs Automatically
    11.2. Using Files to Specify the Stub Bodies
    11.3. Alternative: Using JUnit Rules
    11.4. Relaxed SSL Validation for Rest Template
    11.5. WireMock and Spring MVC Mocks
    11.6. Customization of WireMock configuration
    11.7. Generating Stubs using REST Docs
    11.8. Generating Contracts by Using REST Docs
    12. Migrations
    12.1. 1.0.x → 1.1.x
    12.1.1. New structure of generated stubs
    12.2. 1.1.x → 1.2.x
    12.2.1. Custom HttpServerStub
    12.2.2. New packages for generated tests
    12.2.3. New Methods in TemplateProcessor
    12.2.4. RestAssured 3.0
    12.3. 1.2.x → 2.0.x
    12.3.1. No Camel support
    13. Links
    \ No newline at end of file + Spring Cloud Contract

    Spring Cloud Contract


    Table of Contents

    1. Spring Cloud Contract
    2. Spring Cloud Contract Verifier Introduction
    2.1. Why a Contract Verifier?
    2.1.1. Testing issues
    2.2. Purposes
    2.3. How It Works
    2.3.1. Defining the contract
    2.3.2. Client Side
    2.3.3. Server Side
    2.4. Step-by-step Guide to Consumer Driven Contracts (CDC)
    2.4.1. Technical note
    2.4.2. Consumer side (Loan Issuance)
    2.4.3. Producer side (Fraud Detection server)
    2.4.4. Consumer Side (Loan Issuance) Final Step
    2.5. Dependencies
    2.6. Additional Links
    2.6.1. Spring Cloud Contract video
    2.6.2. Readings
    2.7. Samples
    3. Spring Cloud Contract FAQ
    3.1. Why use Spring Cloud Contract Verifier and not X ?
    3.2. I don’t want to write a contract in Groovy!
    3.3. What is this value(consumer(), producer()) ?
    3.4. How to do Stubs versioning?
    3.4.1. API Versioning
    3.4.2. JAR versioning
    3.4.3. Dev or prod stubs
    3.5. Common repo with contracts
    3.5.1. Repo structure
    3.5.2. Workflow
    3.5.3. Consumer
    3.5.4. Producer
    3.6. Can I have multiple base classes for tests?
    3.7. How can I debug the request/response being sent by the generated tests client?
    3.7.1. How can I debug the mapping/request/response being sent by WireMock?
    3.7.2. How can I see what got registered in the HTTP server stub?
    3.7.3. Can I reference the request from the response?
    3.7.4. Can I reference text from file?
    4. Spring Cloud Contract Verifier Setup
    4.1. Gradle Project
    4.1.1. Prerequisites
    4.1.2. Add Gradle Plugin with Dependencies
    4.1.3. Gradle and Rest Assured 2.0
    4.1.4. Snapshot Versions for Gradle
    4.1.5. Add stubs
    4.1.6. Run the Plugin
    4.1.7. Default Setup
    4.1.8. Configure Plugin
    4.1.9. Configuration Options
    4.1.10. Single Base Class for All Tests
    4.1.11. Different Base Classes for Contracts
    4.1.12. Invoking Generated Tests
    4.1.13. Spring Cloud Contract Verifier on the Consumer Side
    4.2. Maven Project
    4.2.1. Add maven plugin
    4.2.2. Maven and Rest Assured 2.0
    4.2.3. Snapshot versions for Maven
    4.2.4. Add stubs
    4.2.5. Run plugin
    4.2.6. Configure plugin
    4.2.7. Configuration Options
    4.2.8. Single Base Class for All Tests
    4.2.9. Different base classes for contracts
    4.2.10. Invoking generated tests
    4.2.11. Maven Plugin and STS
    4.2.12. Spring Cloud Contract Verifier on the Consumer Side
    4.3. Stubs and Transitive Dependencies
    4.4. Scenarios
    4.5. Docker Project
    4.5.1. Short intro to Maven, JARs and Binary storage
    4.5.2. How it works
    Environment Variables
    4.5.3. Example of usage
    4.5.4. Server side (nodejs)
    5. Spring Cloud Contract Verifier Messaging
    5.1. Integrations
    5.2. Manual Integration Testing
    5.3. Publisher-Side Test Generation
    5.3.1. Scenario 1: No Input Message
    5.3.2. Scenario 2: Output Triggered by Input
    5.3.3. Scenario 3: No Output Message
    5.4. Consumer Stub Generation
    6. Spring Cloud Contract Stub Runner
    6.1. Snapshot versions
    6.2. Publishing Stubs as JARs
    6.3. Stub Runner Core
    6.3.1. Retrieving stubs
    Stub downloading
    Classpath scanning
    6.3.2. Running stubs
    Limitations
    Running using main app
    HTTP Stubs
    Viewing registered mappings
    Messaging Stubs
    6.4. Stub Runner JUnit Rule
    6.4.1. Maven settings
    6.4.2. Providing fixed ports
    6.4.3. Fluent API
    6.4.4. Stub Runner with Spring
    6.5. Stub Runner Spring Cloud
    6.5.1. Stubbing Service Discovery
    Test profiles and service discovery
    6.5.2. Additional Configuration
    6.6. Stub Runner Boot Application
    6.6.1. How to use it?
    Stub Runner Server
    Spring Cloud CLI
    6.6.2. Endpoints
    HTTP
    Messaging
    6.6.3. Example
    6.6.4. Stub Runner Boot with Service Discovery
    6.7. Stubs Per Consumer
    6.8. Common
    6.8.1. Common Properties for JUnit and Spring
    6.8.2. Stub Runner Stubs IDs
    6.9. Stub Runner Docker
    6.9.1. How to use it
    6.9.2. Example of client side usage in a non JVM project
    7. Stub Runner for Messaging
    7.1. Stub triggering
    7.1.1. Trigger by Label
    7.1.2. Trigger by Group and Artifact Ids
    7.1.3. Trigger by Artifact Ids
    7.1.4. Trigger All Messages
    7.2. Stub Runner Integration
    7.2.1. Adding the Runner to the Project
    7.2.2. Disabling the functionality
    Scenario 1 (no input message)
    Scenario 2 (output triggered by input)
    Scenario 3 (input with no output)
    7.3. Stub Runner Stream
    7.3.1. Adding the Runner to the Project
    7.3.2. Disabling the functionality
    Scenario 1 (no input message)
    Scenario 2 (output triggered by input)
    Scenario 3 (input with no output)
    7.4. Stub Runner Spring AMQP
    7.4.1. Adding the Runner to the Project
    Triggering the message
    Spring AMQP Test Configuration
    8. Contract DSL
    8.1. Limitations
    8.2. Common Top-Level elements
    8.2.1. Description
    8.2.2. Name
    8.2.3. Ignoring Contracts
    8.2.4. Passing Values from Files
    8.2.5. HTTP Top-Level Elements
    8.3. Request
    8.4. Response
    8.5. Dynamic properties
    8.5.1. Dynamic properties inside the body
    8.5.2. Regular expressions
    8.5.3. Passing Optional Parameters
    8.5.4. Executing Custom Methods on the Server Side
    8.5.5. Referencing the Request from the Response
    8.5.6. Registering Your Own WireMock Extension
    8.5.7. Dynamic Properties in the Matchers Sections
    8.6. JAX-RS Support
    8.7. Async Support
    8.8. Working with Context Paths
    8.9. Messaging Top-Level Elements
    8.9.1. Output Triggered by a Method
    8.9.2. Output Triggered by a Message
    8.9.3. Consumer/Producer
    8.9.4. Common
    8.10. Multiple Contracts in One File
    9. Customization
    9.1. Extending the DSL
    9.1.1. Common JAR
    9.1.2. Adding the Dependency to the Project
    9.1.3. Test the Dependency in the Project’s Dependencies
    9.1.4. Test a Dependency in the Plugin’s Dependencies
    9.1.5. Referencing classes in DSLs
    10. Using the Pluggable Architecture
    10.1. Custom Contract Converter
    10.1.1. Pact Converter
    10.1.2. Pact Contract
    10.1.3. Pact for Producers
    10.1.4. Pact for Consumers
    10.2. Using the Custom Test Generator
    10.3. Using the Custom Stub Generator
    10.4. Using the Custom Stub Runner
    10.5. Using the Custom Stub Downloader
    11. Spring Cloud Contract WireMock
    11.1. Registering Stubs Automatically
    11.2. Using Files to Specify the Stub Bodies
    11.3. Alternative: Using JUnit Rules
    11.4. Relaxed SSL Validation for Rest Template
    11.5. WireMock and Spring MVC Mocks
    11.6. Customization of WireMock configuration
    11.7. Generating Stubs using REST Docs
    11.8. Generating Contracts by Using REST Docs
    12. Migrations
    12.1. 1.0.x → 1.1.x
    12.1.1. New structure of generated stubs
    12.2. 1.1.x → 1.2.x
    12.2.1. Custom HttpServerStub
    12.2.2. New packages for generated tests
    12.2.3. New Methods in TemplateProcessor
    12.2.4. RestAssured 3.0
    12.3. 1.2.x → 2.0.x
    12.3.1. No Camel support
    13. Links
    \ No newline at end of file diff --git a/single/spring-cloud-contract.html b/single/spring-cloud-contract.html index 7ddfbe4cc0..7e72cb0c5e 100644 --- a/single/spring-cloud-contract.html +++ b/single/spring-cloud-contract.html @@ -1,6 +1,6 @@ - Spring Cloud Contract

    Spring Cloud Contract


    Table of Contents

    1. Spring Cloud Contract
    2. Spring Cloud Contract Verifier Introduction
    2.1. Why a Contract Verifier?
    2.1.1. Testing issues
    2.2. Purposes
    2.3. How It Works
    2.3.1. Defining the contract
    2.3.2. Client Side
    2.3.3. Server Side
    2.4. Step-by-step Guide to Consumer Driven Contracts (CDC)
    2.4.1. Technical note
    2.4.2. Consumer side (Loan Issuance)
    2.4.3. Producer side (Fraud Detection server)
    2.4.4. Consumer Side (Loan Issuance) Final Step
    2.5. Dependencies
    2.6. Additional Links
    2.6.1. Spring Cloud Contract video
    2.6.2. Readings
    2.7. Samples
    3. Spring Cloud Contract FAQ
    3.1. Why use Spring Cloud Contract Verifier and not X ?
    3.2. What is this value(consumer(), producer()) ?
    3.3. How to do Stubs versioning?
    3.3.1. API Versioning
    3.3.2. JAR versioning
    3.3.3. Dev or prod stubs
    3.4. Common repo with contracts
    3.4.1. Repo structure
    3.4.2. Workflow
    3.4.3. Consumer
    3.4.4. Producer
    3.5. Can I have multiple base classes for tests?
    3.6. How can I debug the request/response being sent by the generated tests client?
    3.6.1. How can I debug the mapping/request/response being sent by WireMock?
    3.6.2. How can I see what got registered in the HTTP server stub?
    3.6.3. Can I reference the request from the response?
    3.6.4. Can I reference text from file?
    4. Spring Cloud Contract Verifier Setup
    4.1. Gradle Project
    4.1.1. Prerequisites
    4.1.2. Add Gradle Plugin with Dependencies
    4.1.3. Gradle and Rest Assured 2.0
    4.1.4. Snapshot Versions for Gradle
    4.1.5. Add stubs
    4.1.6. Run the Plugin
    4.1.7. Default Setup
    4.1.8. Configure Plugin
    4.1.9. Configuration Options
    4.1.10. Single Base Class for All Tests
    4.1.11. Different Base Classes for Contracts
    4.1.12. Invoking Generated Tests
    4.1.13. Spring Cloud Contract Verifier on the Consumer Side
    4.2. Maven Project
    4.2.1. Add maven plugin
    4.2.2. Maven and Rest Assured 2.0
    4.2.3. Snapshot versions for Maven
    4.2.4. Add stubs
    4.2.5. Run plugin
    4.2.6. Configure plugin
    4.2.7. Configuration Options
    4.2.8. Single Base Class for All Tests
    4.2.9. Different base classes for contracts
    4.2.10. Invoking generated tests
    4.2.11. Maven Plugin and STS
    4.2.12. Spring Cloud Contract Verifier on the Consumer Side
    4.3. Stubs and Transitive Dependencies
    4.4. Scenarios
    5. Spring Cloud Contract Verifier Messaging
    5.1. Integrations
    5.2. Manual Integration Testing
    5.3. Publisher-Side Test Generation
    5.3.1. Scenario 1: No Input Message
    5.3.2. Scenario 2: Output Triggered by Input
    5.3.3. Scenario 3: No Output Message
    5.4. Consumer Stub Generation
    6. Spring Cloud Contract Stub Runner
    6.1. Snapshot versions
    6.2. Publishing Stubs as JARs
    6.3. Stub Runner Core
    6.3.1. Retrieving stubs
    Stub downloading
    Classpath scanning
    6.3.2. Running stubs
    Limitations
    Running using main app
    HTTP Stubs
    Viewing registered mappings
    Messaging Stubs
    6.4. Stub Runner JUnit Rule
    6.4.1. Maven settings
    6.4.2. Providing fixed ports
    6.4.3. Fluent API
    6.4.4. Stub Runner with Spring
    6.5. Stub Runner Spring Cloud
    6.5.1. Stubbing Service Discovery
    Test profiles and service discovery
    6.5.2. Additional Configuration
    6.6. Stub Runner Boot Application
    6.6.1. How to use it?
    Stub Runner Server
    Spring Cloud CLI
    6.6.2. Endpoints
    HTTP
    Messaging
    6.6.3. Example
    6.6.4. Stub Runner Boot with Service Discovery
    6.7. Stubs Per Consumer
    6.8. Common
    6.8.1. Common Properties for JUnit and Spring
    6.8.2. Stub Runner Stubs IDs
    7. Stub Runner for Messaging
    7.1. Stub triggering
    7.1.1. Trigger by Label
    7.1.2. Trigger by Group and Artifact Ids
    7.1.3. Trigger by Artifact Ids
    7.1.4. Trigger All Messages
    7.2. Stub Runner Integration
    7.2.1. Adding the Runner to the Project
    7.2.2. Disabling the functionality
    Scenario 1 (no input message)
    Scenario 2 (output triggered by input)
    Scenario 3 (input with no output)
    7.3. Stub Runner Stream
    7.3.1. Adding the Runner to the Project
    7.3.2. Disabling the functionality
    Scenario 1 (no input message)
    Scenario 2 (output triggered by input)
    Scenario 3 (input with no output)
    7.4. Stub Runner Spring AMQP
    7.4.1. Adding the Runner to the Project
    Triggering the message
    Spring AMQP Test Configuration
    8. Contract DSL
    8.1. Limitations
    8.2. Common Top-Level elements
    8.2.1. Description
    8.2.2. Name
    8.2.3. Ignoring Contracts
    8.2.4. Passing Values from Files
    8.2.5. HTTP Top-Level Elements
    8.3. Request
    8.4. Response
    8.5. Dynamic properties
    8.5.1. Dynamic properties inside the body
    8.5.2. Regular expressions
    8.5.3. Passing Optional Parameters
    8.5.4. Executing Custom Methods on the Server Side
    8.5.5. Referencing the Request from the Response
    8.5.6. Registering Your Own WireMock Extension
    8.5.7. Dynamic Properties in the Matchers Sections
    8.6. JAX-RS Support
    8.7. Async Support
    8.8. Working with Context Paths
    8.9. Messaging Top-Level Elements
    8.9.1. Output Triggered by a Method
    8.9.2. Output Triggered by a Message
    8.9.3. Consumer/Producer
    8.9.4. Common
    8.10. Multiple Contracts in One File
    9. Customization
    9.1. Extending the DSL
    9.1.1. Common JAR
    9.1.2. Adding the Dependency to the Project
    9.1.3. Test the Dependency in the Project’s Dependencies
    9.1.4. Test a Dependency in the Plugin’s Dependencies
    9.1.5. Referencing classes in DSLs
    10. Using the Pluggable Architecture
    10.1. Custom Contract Converter
    10.1.1. Pact Converter
    10.1.2. Pact Contract
    10.1.3. Pact for Producers
    10.1.4. Pact for Consumers
    10.2. Using the Custom Test Generator
    10.3. Using the Custom Stub Generator
    10.4. Using the Custom Stub Runner
    10.5. Using the Custom Stub Downloader
    11. Spring Cloud Contract WireMock
    11.1. Registering Stubs Automatically
    11.2. Using Files to Specify the Stub Bodies
    11.3. Alternative: Using JUnit Rules
    11.4. Relaxed SSL Validation for Rest Template
    11.5. WireMock and Spring MVC Mocks
    11.6. Customization of WireMock configuration
    11.7. Generating Stubs using REST Docs
    11.8. Generating Contracts by Using REST Docs
    12. Migrations
    12.1. 1.0.x → 1.1.x
    12.1.1. New structure of generated stubs
    12.2. 1.1.x → 1.2.x
    12.2.1. Custom HttpServerStub
    12.2.2. New packages for generated tests
    12.2.3. New Methods in TemplateProcessor
    12.2.4. RestAssured 3.0
    12.3. 1.2.x → 2.0.x
    12.3.1. No Camel support
    13. Links

    _Documentation Authors: Adam Dudczak, Mathias Düsterhöft, Marcin Grzejszczak, Dennis Kieselhorst, Jakub Kubryński, Karol Lassak, + Spring Cloud Contract

    Spring Cloud Contract


    Table of Contents

    1. Spring Cloud Contract
    2. Spring Cloud Contract Verifier Introduction
    2.1. Why a Contract Verifier?
    2.1.1. Testing issues
    2.2. Purposes
    2.3. How It Works
    2.3.1. Defining the contract
    2.3.2. Client Side
    2.3.3. Server Side
    2.4. Step-by-step Guide to Consumer Driven Contracts (CDC)
    2.4.1. Technical note
    2.4.2. Consumer side (Loan Issuance)
    2.4.3. Producer side (Fraud Detection server)
    2.4.4. Consumer Side (Loan Issuance) Final Step
    2.5. Dependencies
    2.6. Additional Links
    2.6.1. Spring Cloud Contract video
    2.6.2. Readings
    2.7. Samples
    3. Spring Cloud Contract FAQ
    3.1. Why use Spring Cloud Contract Verifier and not X ?
    3.2. I don’t want to write a contract in Groovy!
    3.3. What is this value(consumer(), producer()) ?
    3.4. How to do Stubs versioning?
    3.4.1. API Versioning
    3.4.2. JAR versioning
    3.4.3. Dev or prod stubs
    3.5. Common repo with contracts
    3.5.1. Repo structure
    3.5.2. Workflow
    3.5.3. Consumer
    3.5.4. Producer
    3.6. Can I have multiple base classes for tests?
    3.7. How can I debug the request/response being sent by the generated tests client?
    3.7.1. How can I debug the mapping/request/response being sent by WireMock?
    3.7.2. How can I see what got registered in the HTTP server stub?
    3.7.3. Can I reference the request from the response?
    3.7.4. Can I reference text from file?
    4. Spring Cloud Contract Verifier Setup
    4.1. Gradle Project
    4.1.1. Prerequisites
    4.1.2. Add Gradle Plugin with Dependencies
    4.1.3. Gradle and Rest Assured 2.0
    4.1.4. Snapshot Versions for Gradle
    4.1.5. Add stubs
    4.1.6. Run the Plugin
    4.1.7. Default Setup
    4.1.8. Configure Plugin
    4.1.9. Configuration Options
    4.1.10. Single Base Class for All Tests
    4.1.11. Different Base Classes for Contracts
    4.1.12. Invoking Generated Tests
    4.1.13. Spring Cloud Contract Verifier on the Consumer Side
    4.2. Maven Project
    4.2.1. Add maven plugin
    4.2.2. Maven and Rest Assured 2.0
    4.2.3. Snapshot versions for Maven
    4.2.4. Add stubs
    4.2.5. Run plugin
    4.2.6. Configure plugin
    4.2.7. Configuration Options
    4.2.8. Single Base Class for All Tests
    4.2.9. Different base classes for contracts
    4.2.10. Invoking generated tests
    4.2.11. Maven Plugin and STS
    4.2.12. Spring Cloud Contract Verifier on the Consumer Side
    4.3. Stubs and Transitive Dependencies
    4.4. Scenarios
    4.5. Docker Project
    4.5.1. Short intro to Maven, JARs and Binary storage
    4.5.2. How it works
    Environment Variables
    4.5.3. Example of usage
    4.5.4. Server side (nodejs)
    5. Spring Cloud Contract Verifier Messaging
    5.1. Integrations
    5.2. Manual Integration Testing
    5.3. Publisher-Side Test Generation
    5.3.1. Scenario 1: No Input Message
    5.3.2. Scenario 2: Output Triggered by Input
    5.3.3. Scenario 3: No Output Message
    5.4. Consumer Stub Generation
    6. Spring Cloud Contract Stub Runner
    6.1. Snapshot versions
    6.2. Publishing Stubs as JARs
    6.3. Stub Runner Core
    6.3.1. Retrieving stubs
    Stub downloading
    Classpath scanning
    6.3.2. Running stubs
    Limitations
    Running using main app
    HTTP Stubs
    Viewing registered mappings
    Messaging Stubs
    6.4. Stub Runner JUnit Rule
    6.4.1. Maven settings
    6.4.2. Providing fixed ports
    6.4.3. Fluent API
    6.4.4. Stub Runner with Spring
    6.5. Stub Runner Spring Cloud
    6.5.1. Stubbing Service Discovery
    Test profiles and service discovery
    6.5.2. Additional Configuration
    6.6. Stub Runner Boot Application
    6.6.1. How to use it?
    Stub Runner Server
    Spring Cloud CLI
    6.6.2. Endpoints
    HTTP
    Messaging
    6.6.3. Example
    6.6.4. Stub Runner Boot with Service Discovery
    6.7. Stubs Per Consumer
    6.8. Common
    6.8.1. Common Properties for JUnit and Spring
    6.8.2. Stub Runner Stubs IDs
    6.9. Stub Runner Docker
    6.9.1. How to use it
    6.9.2. Example of client side usage in a non JVM project
    7. Stub Runner for Messaging
    7.1. Stub triggering
    7.1.1. Trigger by Label
    7.1.2. Trigger by Group and Artifact Ids
    7.1.3. Trigger by Artifact Ids
    7.1.4. Trigger All Messages
    7.2. Stub Runner Integration
    7.2.1. Adding the Runner to the Project
    7.2.2. Disabling the functionality
    Scenario 1 (no input message)
    Scenario 2 (output triggered by input)
    Scenario 3 (input with no output)
    7.3. Stub Runner Stream
    7.3.1. Adding the Runner to the Project
    7.3.2. Disabling the functionality
    Scenario 1 (no input message)
    Scenario 2 (output triggered by input)
    Scenario 3 (input with no output)
    7.4. Stub Runner Spring AMQP
    7.4.1. Adding the Runner to the Project
    Triggering the message
    Spring AMQP Test Configuration
    8. Contract DSL
    8.1. Limitations
    8.2. Common Top-Level elements
    8.2.1. Description
    8.2.2. Name
    8.2.3. Ignoring Contracts
    8.2.4. Passing Values from Files
    8.2.5. HTTP Top-Level Elements
    8.3. Request
    8.4. Response
    8.5. Dynamic properties
    8.5.1. Dynamic properties inside the body
    8.5.2. Regular expressions
    8.5.3. Passing Optional Parameters
    8.5.4. Executing Custom Methods on the Server Side
    8.5.5. Referencing the Request from the Response
    8.5.6. Registering Your Own WireMock Extension
    8.5.7. Dynamic Properties in the Matchers Sections
    8.6. JAX-RS Support
    8.7. Async Support
    8.8. Working with Context Paths
    8.9. Messaging Top-Level Elements
    8.9.1. Output Triggered by a Method
    8.9.2. Output Triggered by a Message
    8.9.3. Consumer/Producer
    8.9.4. Common
    8.10. Multiple Contracts in One File
    9. Customization
    9.1. Extending the DSL
    9.1.1. Common JAR
    9.1.2. Adding the Dependency to the Project
    9.1.3. Test the Dependency in the Project’s Dependencies
    9.1.4. Test a Dependency in the Plugin’s Dependencies
    9.1.5. Referencing classes in DSLs
    10. Using the Pluggable Architecture
    10.1. Custom Contract Converter
    10.1.1. Pact Converter
    10.1.2. Pact Contract
    10.1.3. Pact for Producers
    10.1.4. Pact for Consumers
    10.2. Using the Custom Test Generator
    10.3. Using the Custom Stub Generator
    10.4. Using the Custom Stub Runner
    10.5. Using the Custom Stub Downloader
    11. Spring Cloud Contract WireMock
    11.1. Registering Stubs Automatically
    11.2. Using Files to Specify the Stub Bodies
    11.3. Alternative: Using JUnit Rules
    11.4. Relaxed SSL Validation for Rest Template
    11.5. WireMock and Spring MVC Mocks
    11.6. Customization of WireMock configuration
    11.7. Generating Stubs using REST Docs
    11.8. Generating Contracts by Using REST Docs
    12. Migrations
    12.1. 1.0.x → 1.1.x
    12.1.1. New structure of generated stubs
    12.2. 1.1.x → 1.2.x
    12.2.1. Custom HttpServerStub
    12.2.2. New packages for generated tests
    12.2.3. New Methods in TemplateProcessor
    12.2.4. RestAssured 3.0
    12.3. 1.2.x → 2.0.x
    12.3.1. No Camel support
    13. Links

    _Documentation Authors: Adam Dudczak, Mathias Düsterhöft, Marcin Grzejszczak, Dennis Kieselhorst, Jakub Kubryński, Karol Lassak, Olga Maciaszek-Sharma, Mariusz Smykuła, Dave Syer, Jay Bryant

    2.0.0.BUILD-SNAPSHOT

    1. Spring Cloud Contract

    You need confidence when pushing new features to a new application or service in a distributed system. This project provides support for Consumer Driven Contracts and service schemas in Spring applications (for both HTTP and message-based interactions), @@ -32,7 +32,8 @@ contracts, one for the positive case and one for the negative case. Contract tes used to test contracts between applications and not to simulate full behavior.

    2.3 How It Works

    This section explores how Spring Cloud Contract Verifier with Stub Runner works.

    2.3.1 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.

    package contracts
    +the PUT method.

    Groovy DSL.  +

    package contracts
     
     org.springframework.cloud.contract.spec.Contract.make {
     	request { // (1)
    @@ -88,7 +89,61 @@ From the Producer perspective, in the autogenerated producer-side test:
     (8) - and JSON body equal to
      { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
     (9) - with header `Content-Type` matching `application/json.*`
    - */

    2.3.2 Client Side

    Spring Cloud Contract generates stubs, which you can use during client-side testing. + */

    +

    YAML.  +

    request: # (1)
    +  method: PUT # (2)
    +  url: /fraudcheck # (3)
    +  body: # (4)
    +    "client.id": 1234567890
    +    loanAmount: 99999
    +  headers: # (5)
    +    Content-Type: application/json
    +  matchers:
    +    body:
    +      - path: $.['client.id'] # (6)
    +        type: by_regex
    +        value: "[0-9]{10}"
    +response: # (7)
    +  status: 200 # (8)
    +  body:  # (9)
    +    fraudCheckStatus: "FRAUD"
    +    "rejection.reason": "Amount too high"
    +  headers: # (10)
    +    Content-Type: application/json;charset=UTF-8
    +
    +
    +#From the Consumer perspective, when shooting a request in the integration test:
    +#
    +#(1) - If the consumer sends a request
    +#(2) - With the "PUT" method
    +#(3) - to the URL "/fraudcheck"
    +#(4) - with the JSON body that
    +# * has a field `clientId`
    +# * has a field `loanAmount` that is equal to `99999`
    +#(5) - with header `Content-Type` equal to `application/json`
    +#(6) - and a `client.id` json entry matches the regular expression `[0-9]{10}`
    +#(7) - then the response will be sent with
    +#(8) - status equal `200`
    +#(9) - and JSON body equal to
    +# { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
    +#(10) - with header `Content-Type` equal to `application/json`
    +#
    +#From the Producer perspective, in the autogenerated producer-side test:
    +#
    +#(1) - A request will be sent to the producer
    +#(2) - With the "PUT" method
    +#(3) - to the URL "/fraudcheck"
    +#(4) - with the JSON body that
    +# * has a field `clientId` `1234567890`
    +# * has a field `loanAmount` that is equal to `99999`
    +#(5) - with header `Content-Type` equal to `application/json`
    +#(7) - then the test will assert if the response has been sent with
    +#(8) - status equal `200`
    +#(9) - and JSON body equal to
    +# { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
    +#(10) - with header `Content-Type` equal to `application/json;charset=UTF-8`

    +

    2.3.2 Client Side

    Spring Cloud Contract generates stubs, which you can use during client-side testing. 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,
    @@ -103,7 +158,7 @@ You would like to feed that instance with a proper stub definition.

    At som (or random) port.

    2.3.3 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 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()
    @@ -212,9 +267,10 @@ client wants to borrow. You want to send it to the /fraudc
     				FraudServiceResponse.class);

    For simplicity, the port of the Fraud Detection service is set to 8080, and the application runs on 8090.

    If you start the test at this point, it breaks, because no service currently runs on port 8080.

    Clone the Fraud Detection service repository locally.

    You can start by playing around with the server side contract. To do so, you must first -clone it.

    git clone https://your-git-server.com/server-side.git local-http-server-repo

    Define the contract locally in the repo of Fraud Detection service.

    As a consumer, you need to define what exactly you want to achieve. You need to formulate +clone it.

    $ git clone https://your-git-server.com/server-side.git local-http-server-repo

    Define the contract locally in the repo of Fraud Detection service.

    As a consumer, you need to define what exactly you want to achieve. You need to formulate your expectations. To do so, write the following contract:

    [Important]Important

    Place the contract under src/test/resources/contracts/fraud folder. The fraud folder -is important because the producer’s test base class name references that folder.

    package contracts
    +is important because the producer’s test base class name references that folder.

    Groovy DSL.  +

    package contracts
     
     org.springframework.cloud.contract.spec.Contract.make {
     	request { // (1)
    @@ -270,8 +326,63 @@ From the Producer perspective, in the autogenerated producer-side test:
     (8) - and JSON body equal to
      { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
     (9) - with header `Content-Type` matching `application/json.*`
    - */

    The Contract is written using a statically typed Groovy DSL. You might wonder what about -those value(client(…​), server(…​)) parts. By using this notation, Spring Cloud + */

    +

    YAML.  +

    request: # (1)
    +  method: PUT # (2)
    +  url: /fraudcheck # (3)
    +  body: # (4)
    +    "client.id": 1234567890
    +    loanAmount: 99999
    +  headers: # (5)
    +    Content-Type: application/json
    +  matchers:
    +    body:
    +      - path: $.['client.id'] # (6)
    +        type: by_regex
    +        value: "[0-9]{10}"
    +response: # (7)
    +  status: 200 # (8)
    +  body:  # (9)
    +    fraudCheckStatus: "FRAUD"
    +    "rejection.reason": "Amount too high"
    +  headers: # (10)
    +    Content-Type: application/json;charset=UTF-8
    +
    +
    +#From the Consumer perspective, when shooting a request in the integration test:
    +#
    +#(1) - If the consumer sends a request
    +#(2) - With the "PUT" method
    +#(3) - to the URL "/fraudcheck"
    +#(4) - with the JSON body that
    +# * has a field `clientId`
    +# * has a field `loanAmount` that is equal to `99999`
    +#(5) - with header `Content-Type` equal to `application/json`
    +#(6) - and a `client.id` json entry matches the regular expression `[0-9]{10}`
    +#(7) - then the response will be sent with
    +#(8) - status equal `200`
    +#(9) - and JSON body equal to
    +# { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
    +#(10) - with header `Content-Type` equal to `application/json`
    +#
    +#From the Producer perspective, in the autogenerated producer-side test:
    +#
    +#(1) - A request will be sent to the producer
    +#(2) - With the "PUT" method
    +#(3) - to the URL "/fraudcheck"
    +#(4) - with the JSON body that
    +# * has a field `clientId` `1234567890`
    +# * has a field `loanAmount` that is equal to `99999`
    +#(5) - with header `Content-Type` equal to `application/json`
    +#(7) - then the test will assert if the response has been sent with
    +#(8) - status equal `200`
    +#(9) - and JSON body equal to
    +# { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
    +#(10) - with header `Content-Type` equal to `application/json;charset=UTF-8`

    +

    The YML contract is quite straight-forward. However when you take a look at the Contract +written using a statically typed Groovy DSL - you might wonder what the +value(client(…​), server(…​)) parts are. By using this notation, Spring Cloud Contract lets you define parts of a JSON block, a URL, etc., which are dynamic. In case of an identifier or a timestamp, you need not hardcode a value. You want to allow some different ranges of values. To enable ranges of values, you can set regular expressions @@ -303,8 +414,8 @@ First, add the Spring Cloud Contract BOM.

    </configuration>
     </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 ---
    +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
     [INFO]
     [INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ http-server ---
    @@ -354,8 +465,8 @@ you wish.

    Once you are satisfied with the results and the test passes, pub the server side. Currently, the consumer side work is done.

    2.4.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>
    +}

    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>
     	<groupId>org.springframework.cloud</groupId>
     	<artifactId>spring-cloud-starter-contract-verifier</artifactId>
     	<scope>test</scope>
    @@ -425,8 +536,9 @@ like this:

    "['fraudCheckStatus']").matches("[A-Z]{5}");
             assertThatJson(parsedJson).field("['rejection.reason']").isEqualTo("Amount too high");
    -}

    As you can see, all the producer() parts of the Contract that were present in the -value(consumer(…​), producer(…​)) blocks got injected into the test.

    Note that, on the producer side, you are also doing TDD. The expectations are expressed +}

    If you used the Groovy DSL, you can see, all the producer() parts of the Contract that were present in the +value(consumer(…​), producer(…​)) blocks got injected into the test. +In case of using YAML, the same applied for the matchers sections of the response.

    Note that, on the producer side, you are also doing TDD. The expectations are expressed in the form of a test. This test sends a request to our own application with the URL, 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 @@ -439,11 +551,11 @@ implementation:

    return new FraudCheckResult(FraudCheckStatus.OK, NO_REASON);
     }

    When you execute ./mvnw clean install again, the tests pass. Since the Spring Cloud Contract Verifier plugin adds the tests to the generated-test-sources, you can -actually run those tests from your IDE.

    Deploy your app.

    Once you finish your work, you can deploy your change. First, merge the branch:

    git checkout master
    -git merge --no-ff contract-change-pr
    -git push origin master

    Your CI might run something like ./mvnw clean deploy, which would publish both the -application and the stub artifacts.

    2.4.4 Consumer Side (Loan Issuance) Final Step

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

    Merge branch to master.

    git checkout master
    -git merge --no-ff contract-change-pr

    Work online.

    Now you can disable the offline work for Spring Cloud Contract Stub Runner and indicate +actually run those tests from your IDE.

    Deploy your app.

    Once you finish your work, you can deploy your change. First, merge the branch:

    $ git checkout master
    +$ git merge --no-ff contract-change-pr
    +$ git push origin master

    Your CI might run something like ./mvnw clean deploy, which would publish both the +application and the stub artifacts.

    2.4.4 Consumer Side (Loan Issuance) Final Step

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

    Merge branch to master.

    $ git checkout master
    +$ git merge --no-ff contract-change-pr

    Work online.

    Now you can disable the offline work for Spring Cloud Contract Stub Runner and indicate where the repository with your stubs is located. At this moment the stubs of the server side are automatically downloaded from Nexus/Artifactory. You can set the value of stubsMode to REMOTE. The following code shows an example of @@ -455,7 +567,7 @@ that some may be outdated, because the Spring Cloud Contract Verifier project is constant development.

    2.6.1 Spring Cloud Contract video

    You can check out the video from the Warsaw JUG about Spring Cloud Contract:

    2.7 Samples

    You can find some samples at samples.

    3. Spring Cloud Contract FAQ

    3.1 Why use Spring Cloud Contract Verifier and not X ?

    For the time being Spring Cloud Contract Verifier is a JVM based tool. So it could be your first pick when you’re already creating software for the JVM. This project has a lot of really interesting features but especially quite a few of them definitely make -Spring Cloud Contract Verifier stand out on the "market" of Consumer Driven Contract (CDC) tooling. Out of many the most interesting are:

    • Possibility to do CDC with messaging
    • Clear and easy to use, statically typed DSL
    • Possibility to copy paste your current JSON file to the contract and only edit its elements
    • Automatic generation of tests from the defined Contract
    • Stub Runner functionality - the stubs are automatically downloaded at runtime from Nexus / Artifactory
    • Spring Cloud integration - no discovery service is needed for integration tests

    3.2 What is this value(consumer(), producer()) ?

    One of the biggest challenges related to stubs is their reusability. Only if they can be vastly used, will they serve their purpose. +Spring Cloud Contract Verifier stand out on the "market" of Consumer Driven Contract (CDC) tooling. Out of many the most interesting are:

    • Possibility to do CDC with messaging
    • Clear and easy to use, statically typed DSL
    • Possibility to copy paste your current JSON file to the contract and only edit its elements
    • Automatic generation of tests from the defined Contract
    • Stub Runner functionality - the stubs are automatically downloaded at runtime from Nexus / Artifactory
    • Spring Cloud integration - no discovery service is needed for integration tests

    3.2 I don’t want to write a contract in Groovy!

    No problem. You can write a contract in YAML!

    3.3 What is this value(consumer(), producer()) ?

    One of the biggest challenges related to stubs is their reusability. Only if they can be vastly used, will they serve their purpose. What typically makes that difficult are the hard-coded values of request / response elements. For example dates or ids. Imagine the following JSON request

    {
         "time" : "2016-10-10 20:10:15",
    @@ -521,19 +633,19 @@ for time and UUID are simplified and most likely invalid but we want to keep thi
     					])
     			}
     }
    [Important]Important

    Please read the Groovy docs related to JSON to understand how to -properly structure the request / response bodies.

    3.3 How to do Stubs versioning?

    3.3.1 API Versioning

    Let’s try to answer a question what versioning really means. If you’re referring to the API version then there are +properly structure the request / response bodies.

    3.4 How to do Stubs versioning?

    3.4.1 API Versioning

    Let’s try to answer a question what versioning really means. If you’re referring to the API version then there are different approaches.

    • use Hypermedia, links and do not version your API by any means
    • pass versions through headers / urls

    I will not try to answer a question which approach is better. Whatever suit your needs and allows you to generate business value should be picked.

    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 th contract name - whatever suits you more.

    3.3.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 +You can create a subfolder for every version or append it to th 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 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.3.3 Dev or prod stubs

    You can manipulate the classifier to run the tests against current development version of the stubs of other services +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 - once you reach production deployment then you can run tests in one case with dev stubs and one with prod stubs.

    Example of tests using development version of stubs

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

    Example of tests using production version of stubs

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

    You can pass those values also via properties from your deployment pipeline.

    3.4 Common repo with contracts

    Another way of storing contracts other than having them with the producer is keeping them in a common place. + once you reach production deployment then you can run tests in one case with dev stubs and one with prod stubs.

    Example of tests using development version of stubs

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

    Example of tests using production version of stubs

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

    You can pass those values also via properties from your deployment pipeline.

    3.5 Common repo with contracts

    Another way of storing contracts other than having them with the producer is keeping them in a common place. It can be related to security issues where the consumers can’t clone the producer’s code. Also if you keep contracts in a single place then you, as a producer, will know how many consumers you have and which -consumer will you break with your local changes.

    3.4.1 Repo structure

    Let’s assume that we have a producer with coordinates com.example:server and 3 consumers: client1, +consumer will you break with your local changes.

    3.5.1 Repo structure

    Let’s assume that we have a producer with coordinates com.example:server and 3 consumers: client1, client2, client3. Then in the repository with common contracts you would have the following setup (which you can checkout here:

    ├── com
     │   └── example
    @@ -568,7 +680,7 @@ one to one to the contents of the repo.

    Example of a <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> - <version>2.0.0.M6</version> + <version>2.0.0.BUILD-SNAPSHOT</version> <relativePath /> </parent> @@ -724,11 +836,11 @@ Those poms are necessary for the consumer side to run mvn </excludes> </fileSet> </fileSets> -</assembly>

    3.4.2 Workflow

    The workflow would look similar to the one presented in the Step by step guide to CDC. The only difference +</assembly>

    3.5.2 Workflow

    The workflow would look similar to the one presented in the Step by step guide to CDC. The only difference is that the producer doesn’t own the contracts anymore. So the consumer and the producer have to work on - common contracts in a common repository.

    3.4.3 Consumer

    When the consumer wants to work on the contracts offline, instead of cloning the producer code, the + common contracts in a common repository.

    3.5.3 Consumer

    When the consumer wants to work on the contracts offline, instead of cloning the producer code, the consumer team clones the common repository, goes to the required producer’s folder (e.g. com/example/server) -and runs mvn clean install -DskipTests to install locally the stubs converted from the contracts.

    [Tip]Tip

    You need to have Maven installed locally

    3.4.4 Producer

    As a producer it’s enough to alter the Spring Cloud Contract Verifier to provide the URL and the dependency +and runs mvn clean install -DskipTests to install locally the stubs converted from the contracts.

    [Tip]Tip

    You need to have Maven installed locally

    3.5.4 Producer

    As a producer it’s enough to alter the Spring Cloud Contract Verifier to provide the URL and the dependency of the JAR containing the contracts:

    <plugin>
     	<groupId>org.springframework.cloud</groupId>
     	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
    @@ -744,15 +856,16 @@ of the JAR containing the contracts:

    http://link/to/your/nexus/or/artifactory/or/sth. It will be then unpacked in a local temporary folder
     and contracts present under the com/example/server will be picked as the ones used to generate the
     tests and the stubs. Due to this convention the producer team will know which consumer teams will be broken
    -when some incompatible changes are done.

    The rest of the flow looks the same.

    3.5 Can I have multiple base classes for tests?

    Yes! Check out the Different base classes for contracts sections -of either Gradle or Maven plugins.

    3.6 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.6.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 +when some incompatible changes are done.

    The rest of the flow looks the same.

    3.6 Can I have multiple base classes for tests?

    Yes! Check out the Different base classes for contracts sections +of either Gradle or Maven plugins.

    3.7 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.7.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 info and the WireMock notifier to being verbose. Now you will exactly know what request was received by WireMock server and which -matching response definition was picked.

    To turn off this feature just bump WireMock logging to ERROR

    logging.level.com.github.tomakehurst.wiremock=ERROR

    3.6.2 How can I see what got registered in the HTTP server stub?

    You can use the mappingsOutputFolder property on @AutoConfigureStubRunner or StubRunnerRule +matching response definition was picked.

    To turn off this feature just bump WireMock logging to ERROR

    logging.level.com.github.tomakehurst.wiremock=ERROR

    3.7.2 How can I see what got registered in the HTTP server stub?

    You can use the mappingsOutputFolder property on @AutoConfigureStubRunner or StubRunnerRule to dump all mappings per artifact id. Also the port at which the given stub server was -started will be attached.

    3.6.3 Can I reference the request from the response?

    Yes! With version 1.1.0 we’ve added such a possibility. On the HTTP stub server side we’re providing support -for this for WireMock. In case of other HTTP server stubs you’ll have to implement the approach yourself.

    3.6.4 Can I reference text from file?

    Yes! With version 1.2.0 we’ve added such a possibility. It’s enough to call file(…​) method in the -DSL and provide a path relative to where the contract lays.

    4. Spring Cloud Contract Verifier Setup

    You can set up Spring Cloud Contract Verifier in either of two ways

    4.1 Gradle Project

    To learn how to set up the Gradle project for Spring Cloud Contract Verifier, read the +started will be attached.

    3.7.3 Can I reference the request from the response?

    Yes! With version 1.1.0 we’ve added such a possibility. On the HTTP stub server side we’re providing support +for this for WireMock. In case of other HTTP server stubs you’ll have to implement the approach yourself.

    3.7.4 Can I reference text from file?

    Yes! With version 1.2.0 we’ve added such a possibility. It’s enough to call file(…​) method in the +DSL and provide a path relative to where the contract lays. +If you’re using YAML just use the bodyFromFile property.

    4. Spring Cloud Contract Verifier Setup

    You can set up Spring Cloud Contract Verifier in the following ways:

    4.1 Gradle Project

    To learn how to set up the Gradle project for Spring Cloud Contract Verifier, read the following sections:

    4.1.1 Prerequisites

    In order to use Spring Cloud Contract Verifier with WireMock, you muse use either a Gradle or a Maven plugin.

    [Warning]Warning

    If you want to use Spock in your projects, you must add separately the spock-core and spock-spring modules. Check Spock @@ -1304,13 +1417,85 @@ optional, they will not get downloaded.

    Creat For example, you might decide to have no dependencies at all.

    Exclude dependencies on the consumer side

    As a consumer, if you add the stub dependency to your classpath, you can explicitly exclude the unwanted dependencies.

    4.4 Scenarios

    You can handle scenarios with Spring Cloud Contract Verifier. All you need to do is to stick to the proper naming convention while creating your contracts. The convention -requires including an order number followed by an underscore, as shown in this example:

    my_contracts_dir\
    +requires including an order number followed by an underscore. This will work regardles
    + of whether you’re working with YAML or Groovy. Example:

    my_contracts_dir\
       scenario1\
         1_login.groovy
         2_showCart.groovy
         3_logout.groovy

    Such a tree causes Spring Cloud Contract Verifier to generate WireMock’s scenario with a name of scenario1 and the three following steps:

    1. login marked as Started pointing to…​
    2. showCart marked as Step1 pointing to…​
    3. logout marked as Step2 which will close the scenario.

    More details about WireMock scenarios can be found at -http://wiremock.org/stateful-behaviour.html

    Spring Cloud Contract Verifier also generates tests with a guaranteed order of execution.

    5. Spring Cloud Contract Verifier Messaging

    Spring Cloud Contract Verifier lets you verify applications that uses messaging as a +http://wiremock.org/stateful-behaviour.html

    Spring Cloud Contract Verifier also generates tests with a guaranteed order of execution.

    4.5 Docker Project

    We’re publishing a springcloud/spring-cloud-contract Docker image +that contains a project that will generate tests and execute them in EXPLICIT mode +against a running application.

    [Tip]Tip

    The EXPLICIT mode means that the tests generated from contracts will send +real requests and not the mocked ones.

    4.5.1 Short intro to Maven, JARs and Binary storage

    Since the Docker image can be used by non JVM projects, it’s good to +explain the basic terms behind Spring Cloud Contract packaging defaults.

    Part of the following definitions were taken from the Maven Glossary

    • Project: Maven thinks in terms of projects. Everything that you +will build are projects. Those projects follow a well defined +“Project Object Model”. Projects can depend on other projects, +in which case the latter are called “dependencies”. A project may +consistent of several subprojects, however these subprojects are still +treated equally as projects.
    • Artifact: An artifact is something that is either produced or used +by a project. Examples of artifacts produced by Maven for a project +include: JARs, source and binary distributions. Each artifact +is uniquely identified by a group id and an artifact ID which is +unique within a group.
    • JAR: JAR stands for Java ARchive. It’s a format based on +the ZIP file format. Spring Cloud Contract packages the contracts and generated +stubs in a JAR file.
    • GroupId: A group ID is a universally unique identifier for a project. +While this is often just the project name (eg. commons-collections), +it is helpful to use a fully-qualified package name to distinguish it +from other projects with a similar name (eg. org.apache.maven). +Typically, when published to the Artifact Manager, the GroupId will get +slash separated and form part of the URL. E.g. for group id com.example +and artifact id application would be /com/example/application/.
    • Classifier: The Maven dependency notation looks as follows: +groupId:artifactId:version:classifier. The classifier is additional suffix +passed to the dependency. E.g. stubs, sources. The same dependency +e.g. com.example:application can produce multiple artifacts that +differ from each other with the classifier.
    • Artifact manager: When you generate binaries / sources / packages, you would +like them to be available for others to download / reference or reuse. In case +of the JVM world those artifacts would be JARs, for Ruby these are gems +and for Docker those would be Docker images. You can store those artifacts +in a manager. Examples of such managers can be Artifactory +or Nexus.

    4.5.2 How it works

    The image searches for contracts under the /contracts folder. +The output from running the tests will be available under +/spring-cloud-contract/build folder (it’s useful for debugging +purposes).

    It’s enough for you to mount your contracts, pass the environment variables + and the image will:

    • generate the contract tests
    • execute the tests against the provided URL
    • generate the WireMock stubs
    • (optional - turned on by default) publish the stubs to a Artifact Manager

    Environment Variables

    The Docker image requires some environment variables to point to +your running application, to the Artifact manager instance etc.

    • PROJECT_GROUP - your project’s group id. Defaults to com.example.
    • PROJECT_VERSION - your project’s version. Defaults to 0.0.1-SNAPSHOT
    • PROJECT_NAME - artifact id. Defaults to example
    • REPO_WITH_BINARIES_URL - URL of your Artifact Manager. Defaults to http://localhost:8081/artifactory/libs-release-local +which is the default URL of Artifactory running locally
    • REPO_WITH_BINARIES_USERNAME - (optional) username when the Artifact Manager is secured
    • REPO_WITH_BINARIES_PASSWORD - (optional) password when the Artifact Manager is secured
    • PUBLISH_ARTIFACTS - if set to true then will publish artifact to binary storage. Defaults to true.

    These environment variables are used when tests are executed:

    • APPLICATION_BASE_URL - url against which tests should be executed. +Remember that it has to be accessible from the Docker container (e.g. localhost +will not work)
    • APPLICATION_USERNAME - (optional) username for basic authentication to your application
    • APPLICATION_PASSWORD - (optional) password for basic authentication to your application

    4.5.3 Example of usage

    Let’s take a look at a simple MVC application

    $ git clone https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs
    +$ cd bookstore

    The contracts are available under /contracts folder.

    4.5.4 Server side (nodejs)

    Since we want to run tests, we could just execute:

    $ npm test

    however, for learning purposes, let’s split it into pieces:

    # Stop docker infra (nodejs, artifactory)
    +$ ./stop_infra.sh
    +# Start docker infra (nodejs, artifactory)
    +$ ./setup_infra.sh
    +
    +# Kill & Run app
    +$ pkill -f "node app"
    +$ nohup node app &
    +
    +# Prepare environment variables
    +$ SC_CONTRACT_DOCKER_VERSION="..."
    +$ APP_IP="192.168.0.100"
    +$ APP_PORT="3000"
    +$ ARTIFACTORY_PORT="8081"
    +$ APPLICATION_BASE_URL="http://${APP_IP}:${APP_PORT}"
    +$ ARTIFACTORY_URL="http://${APP_IP}:${ARTIFACTORY_PORT}/artifactory/libs-release-local"
    +$ CURRENT_DIR="$( pwd )"
    +$ CURRENT_FOLDER_NAME=${PWD##*/}
    +$ PROJECT_VERSION="0.0.1.RELEASE"
    +
    +# Execute contract tests
    +$ docker run  --rm -e "APPLICATION_BASE_URL=${APPLICATION_BASE_URL}" -e "PUBLISH_ARTIFACTS=true" -e "PROJECT_NAME=${CURRENT_FOLDER_NAME}" -e "REPO_WITH_BINARIES_URL=${ARTIFACTORY_URL}" -e "PROJECT_VERSION=${PROJECT_VERSION}" -v "${CURRENT_DIR}/contracts/:/contracts:ro" -v "${CURRENT_DIR}/node_modules/spring-cloud-contract/output:/spring-cloud-contract-output/" springcloud/spring-cloud-contract:"${SC_CONTRACT_DOCKER_VERSION}"
    +
    +# Kill app
    +$ pkill -f "node app"

    What will happen is that via bash scripts:

    • infrastructure will be set up (MongoDb, Artifactory). +In real life scenario you would just run the NodeJS application +with mocked database. In this example we want to show how we can +benefit from Spring Cloud Contract in no time.
    • due to those constraints the contracts also represent the +stateful situation

      • first request is a POST that causes data to get inserted to the database
      • second request is a GET that returns a list of data with 1 previously inserted element
    • the NodeJS application will be started (on port 3000)
    • contract tests will be generated via Docker and tests +will be executed against the running application

      • the contracts will be taken from /contracts folder.
      • the output of the test execution is available under +node_modules/spring-cloud-contract/output.
    • the stubs will be uploaded to Artifactory. You can check them out +under http://localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/ . +The stubs will be here http://localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/bookstore-0.0.1.RELEASE-stubs.jar.

    To see how the client side looks like check out the Section 6.9, “Stub Runner Docker” section.

    5. Spring Cloud Contract Verifier Messaging

    Spring Cloud Contract Verifier lets you verify applications that uses messaging as a means of communication. All of the integrations shown in this document work with Spring, but you can also create one of your own and use that.

    5.1 Integrations

    You can use one of the following four integration configurations:

    • Apache Camel
    • Spring Integration
    • Spring Cloud Stream
    • Spring AMQP

    Since we use Spring Boot, if you have added one of these libraries to the classpath, all the messaging configuration is automatically set up.

    [Important]Important

    Remember to put @AutoConfigureMessageVerifier on the base class of your @@ -1345,7 +1530,8 @@ message is triggered by a component inside the application (for example, schedu meanings for different messaging implementations. For Stream and Integration it is first resolved as a destination of a channel. Then, if there is no such destination it is resolved as a channel name. For Camel, that’s a certain component (for example, -jms).

    5.3.1 Scenario 1: No Input Message

    Here is an example for Camel. For the given contract:

    def contractDsl = Contract.make {
    +jms).

    5.3.1 Scenario 1: No Input Message

    Here is an example for Camel. For the given contract:

    Groovy DSL.  +

    def contractDsl = Contract.make {
     	label 'some_label'
     	input {
     		triggeredBy('bookReturnedTriggered()')
    @@ -1358,7 +1544,19 @@ it is resolved as a channel name. For Camel

    The following JUnit test is created:

    '''
    +}

    +

    YAML.  +

    label: some_label
    +input:
    +  triggeredBy: bookReturnedTriggered
    +outputMessage:
    +  sentTo: activemq:output
    +  body:
    +    bookName: foo
    +  headers:
    +    BOOK-NAME: foo
    +    contentType: application/json

    +

    The following JUnit test is created:

    '''
      // when:
       bookReturnedTriggered();
     
    @@ -1385,7 +1583,8 @@ it is resolved as a channel name. For Camel"bookName").isEqualTo("foo")
     
    -'''

    5.3.2 Scenario 2: Output Triggered by Input

    Here is an example for Camel. For the given contract:

    def contractDsl = Contract.make {
    +'''

    5.3.2 Scenario 2: Output Triggered by Input

    Here is an example for Camel. For the given contract:

    Groovy DSL.  +

    def contractDsl = Contract.make {
     	label 'some_label'
     	input {
     		messageFrom('jms:input')
    @@ -1405,7 +1604,22 @@ it is resolved as a channel name. For Camel'BOOK-NAME', 'foo')
     		}
     	}
    -}

    The following JUnit test is created:

    '''
    +}

    +

    YAML.  +

    label: some_label
    +input:
    +  messageFrom: jms:input
    +  messageBody:
    +    bookName: 'foo'
    +  messageHeaders:
    +    sample: header
    +outputMessage:
    +  sentTo: jms:output
    +  body:
    +    bookName: foo
    +  headers:
    +    BOOK-NAME: foo

    +

    The following JUnit test is created:

    '''
     // given:
      ContractVerifierMessage inputMessage = contractVerifierMessaging.create(
       "{\\"bookName\\":\\"foo\\"}"
    @@ -1440,7 +1654,8 @@ then:
     and:
        DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.payload))
        assertThatJson(parsedJson).field("bookName").isEqualTo("foo")
    -"""

    5.3.3 Scenario 3: No Output Message

    Here is an example for Camel. For the given contract:

    def contractDsl = Contract.make {
    +"""

    5.3.3 Scenario 3: No Output Message

    Here is an example for Camel. For the given contract:

    Groovy DSL.  +

    def contractDsl = Contract.make {
     	label 'some_label'
     	input {
     		messageFrom('jms:delete')
    @@ -1452,7 +1667,17 @@ and:
     		}
     		assertThat('bookWasDeleted()')
     	}
    -}

    The following JUnit test is created:

    '''
    +}

    +

    YAML.  +

    label: some_label
    +input:
    +  messageFrom: jms:delete
    +  messageBody:
    +    bookName: 'foo'
    +  messageHeaders:
    +    sample: header
    +  assertThat: bookWasDeleted()

    +

    The following JUnit test is created:

    '''
     // given:
      ContractVerifierMessage inputMessage = contractVerifierMessaging.create(
     	"{\\"bookName\\":\\"foo\\"}"
    @@ -1618,9 +1843,7 @@ it if you want to.

    Maven.  <inherited>false</inherited> <configuration> <attach>true</attach> - <descriptors> - ${basedir}/src/assembly/stub.xml - </descriptors> + <descriptor>${basedir}/src/assembly/stub.xml</descriptor> </configuration> </execution> </executions> @@ -2217,7 +2440,32 @@ pass an empty classifier this way: groupId:artifactId:vers downloaded.

    port means the port of the WireMock server.

    [Important]Important

    Starting with version 1.0.4, you can provide a range of versions that you would like the Stub Runner to take into consideration. You can read more about the Aether versioning -ranges here.

    7. Stub Runner for Messaging

    Stub Runner can run the published stubs in memory. It can integrate with the following +ranges here.

    6.9 Stub Runner Docker

    We’re publishing a spring-cloud/spring-cloud-contract-stub-runner Docker image +that will start the standalone version of Stub Runner.

    If you want to learn more about the basics of Maven, artifact ids, +group ids, classifiers and Artifact Managers, just click here Section 4.5, “Docker Project”.

    6.9.1 How to use it

    Just execute the docker image. You can pass any of the Section 6.8.1, “Common Properties for JUnit and Spring” +as environment variables. The convention is that all the +letters should be upper case. The camel case notation should +and the dot (.) should be separated via underscore (_). E.g. + the stubrunner.repositoryRoot property should be represented + as a STUBRUNNER_REPOSITORY_ROOT environment variable.

    6.9.2 Example of client side usage in a non JVM project

    We’d like to use the stubs created in this Section 4.5.4, “Server side (nodejs)” step. +Let’s assume that we want to run the stubs on port 9876. The NodeJS code +is available here:

    $ git clone https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs
    +$ cd bookstore

    Let’s run the Stub Runner Boot application with the stubs.

    # Provide the Spring Cloud Contract Docker version
    +$ SC_CONTRACT_DOCKER_VERSION="..."
    +# The IP at which the app is running and Docker container can reach it
    +$ APP_IP="192.168.0.100"
    +# Spring Cloud Contract Stub Runner properties
    +$ STUBRUNNER_PORT="8083"
    +# Stub coordinates 'groupId:artifactId:version:classifier:port'
    +$ STUBRUNNER_IDS="com.example:bookstore:0.0.1.RELEASE:stubs:9876"
    +$ STUBRUNNER_REPOSITORY_ROOT="http://${APP_IP}:8081/artifactory/libs-release-local"
    +# Run the docker with Stub Runner Boot
    +$ docker run  --rm -e "STUBRUNNER_IDS=${STUBRUNNER_IDS}" -e "STUBRUNNER_REPOSITORY_ROOT=${STUBRUNNER_REPOSITORY_ROOT}" -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
    +# Now time for the second request
    +$ curl -X GET http://localhost:9876/api/books
    +# You will receive contents of the JSON

    7. Stub Runner for Messaging

    Stub Runner can run the published stubs in memory. It can integrate with the following frameworks:

    • Spring Integration
    • Spring Cloud Stream
    • Spring AMQP

    It also provides entry points to integrate with any other solution on the market.

    [Important]Important

    If you have multiple frameworks on the classpath Stub Runner will need to define which one should be used. Let’s assume that you have both AMQP, Spring Cloud Stream and Spring Integration on the classpath. Then you need to set stubrunner.stream.enabled=false and stubrunner.integration.enabled=false. @@ -2507,16 +2755,15 @@ definition is matched and invoked with the contract message.

    ConnectionFactory.

    To disable the mocked ConnectionFactory, set the following property: stubrunner.amqp.mockConnection=false

    stubrunner:
       amqp:
    -    mockConnection: false

    8. Contract DSL

    [Important]Important

    Remember that, inside the contract file, you have to provide the fully + mockConnection: false

    8. Contract DSL

    Spring Cloud Contract supports out of the box 2 types of DSL. One written in +Groovy and one written in YAML.

    If you decide to write the contract in Groovy, do not be alarmed if you have not used Groovy +before. Knowledge of the language is not really needed, as the Contract DSL uses only a +tiny subset of it (only literals, method calls and closures). Also, the DSL is statically +typed, to make it programmer-readable without any knowledge of the DSL itself.

    [Important]Important

    Remember that, inside the Groovy contract file, you have to provide the fully qualified name to the Contract class and make static imports, such as org.springframework.cloud.spec.Contract.make { …​ }. You can also provide an import to the Contract class: import org.springframework.cloud.spec.Contract and then call -Contract.make { …​ }.

    Contract DSL is written in Groovy, but do not be alarmed if you have not used Groovy -before. Knowledge of the language is not really needed, as the Contract DSL uses only a -tiny subset of it (only literals, method calls and closures). Also, the DSL is statically -typed, to make it programmer-readable without any knowledge of the DSL itself.

    [Tip]Tip

    Spring Cloud Contract supports defining multiple contracts in a single file.

    The Contract is present in the spring-cloud-contract-spec module of the -Spring -Cloud Contract Verifier repository.

    The following is a complete example of a contract definition:

    org.springframework.cloud.contract.spec.Contract.make {
    +Contract.make { …​ }.

    [Tip]Tip

    Spring Cloud Contract supports defining multiple contracts in a single file.

    The following is a complete example of a Groovy contract definition:

    org.springframework.cloud.contract.spec.Contract.make {
     	request {
     		method 'PUT'
     		url '/api/12'
    @@ -2557,16 +2804,60 @@ Cloud Contract Verifier repository.

    The following is a complete exampl response { status 200 } -}

    [Note]Note

    The preceding example does not contain all the features of the DSL appear. The -remainder of this section describes the other features.

    You can compile Contracts to WireMock stubs mapping using standalone maven command: -mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:convert

    8.1 Limitations

    [Warning]Warning

    Spring Cloud Contract Verifier does not properly support XML. Please use JSON or +}

    The following is a complete example of a YAML contract definition:

    description: Some description
    +name: some name
    +priority: 8
    +ignored: true
    +request:
    +  url: /foo
    +  queryParameters:
    +    a: b
    +    b: c
    +  method: PUT
    +  headers:
    +    foo: bar
    +    fooReq: baz
    +  body:
    +    foo: bar
    +  matchers:
    +    body:
    +      - path: $.foo
    +        type: by_regex
    +        value: bar
    +    headers:
    +      - key: foo
    +        regex: bar
    +response:
    +  status: 200
    +  headers:
    +    foo2: bar
    +    foo3: foo33
    +    fooRes: baz
    +  body:
    +    foo2: bar
    +    foo3: baz
    +  matchers:
    +    body:
    +      - path: $.foo2
    +        type: by_regex
    +        value: bar
    +      - path: $.foo3
    +        type: by_command
    +        value: executeMe($it)
    +    headers:
    +      - key: foo2
    +        regex: bar
    +      - key: foo3
    +        command: andMeToo($it)
    [Tip]Tip

    You can compile contracts to stubs mapping using standalone maven command: +mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:convert

    8.1 Limitations

    [Warning]Warning

    Spring Cloud Contract Verifier does not properly support XML. Please use JSON or help us implement this feature.

    [Warning]Warning

    The support for verifying the size of JSON arrays is experimental. If you want to turn it on, please set the value of the following system property to true: spring.cloud.contract.verifier.assert.size. By default, this feature is set to false. You can also provide the assertJsonSize property in the plugin configuration.

    [Warning]Warning

    Because JSON structure can have any form, it can be impossible to parse it -properly when using the value(consumer(…​), producer(…​)) notation in GString. That +properly when using the Groovy DSL and the value(consumer(…​), producer(…​)) notation in GString. That is why you should use the Groovy Map notation.

    8.2 Common Top-Level elements

    The following sections describe the most common top-level elements:

    8.2.1 Description

    You can add a description to your contract. The description is arbitrary text. The -following code shows an example:

    		org.springframework.cloud.contract.spec.Contract.make {
    +following code shows an example:

    Groovy DSL.  +

    		org.springframework.cloud.contract.spec.Contract.make {
     			description('''
     given:
     	An input
    @@ -2575,23 +2866,81 @@ when:
     then:
     	Output
     ''')
    -		}

    8.2.2 Name

    You can provide a name for your contract. Assume that you provided the following name: + }

    +

    YAML.  +

    description: Some description
    +name: some name
    +priority: 8
    +ignored: true
    +request:
    +  url: /foo
    +  queryParameters:
    +    a: b
    +    b: c
    +  method: PUT
    +  headers:
    +    foo: bar
    +    fooReq: baz
    +  body:
    +    foo: bar
    +  matchers:
    +    body:
    +      - path: $.foo
    +        type: by_regex
    +        value: bar
    +    headers:
    +      - key: foo
    +        regex: bar
    +response:
    +  status: 200
    +  headers:
    +    foo2: bar
    +    foo3: foo33
    +    fooRes: baz
    +  body:
    +    foo2: bar
    +    foo3: baz
    +  matchers:
    +    body:
    +      - path: $.foo2
    +        type: by_regex
    +        value: bar
    +      - path: $.foo3
    +        type: by_command
    +        value: executeMe($it)
    +    headers:
    +      - key: foo2
    +        regex: bar
    +      - key: foo3
    +        command: andMeToo($it)

    +

    8.2.2 Name

    You can provide a name for your contract. Assume that you provided the following name: should register a user. If you do so, the name of the autogenerated test is validate_should_register_a_user. Also, the name of the stub in a WireMock stub is should_register_a_user.json.

    [Important]Important

    You must ensure that the name does not contain any characters that make the generated test not compile. Also, remember that, if you provide the same name for multiple contracts, your autogenerated tests fail to compile and your generated stubs -override each other.

    8.2.3 Ignoring Contracts

    If you want to ignore a contract, you can either set a value of ignored contracts in the -plugin configuration or set the ignored property on the contract itself:

    org.springframework.cloud.contract.spec.Contract.make {
    +override each other.

    Groovy DSL.  +

    org.springframework.cloud.contract.spec.Contract.make {
    +	name("some_special_name")
    +}

    +

    YAML.  +

    name: some name

    +

    8.2.3 Ignoring Contracts

    If you want to ignore a contract, you can either set a value of ignored contracts in the +plugin configuration or set the ignored property on the contract itself:

    Groovy DSL.  +

    org.springframework.cloud.contract.spec.Contract.make {
     	ignored()
    -}

    8.2.4 Passing Values from Files

    Starting with version 1.2.0, you can pass values from files. Assume that you have the +}

    +

    YAML.  +

    ignored: true

    +

    8.2.4 Passing Values from Files

    Starting with version 1.2.0, you can pass values from files. Assume that you have the following resources in our project.

    └── src
         └── test
             └── resources
                 └── contracts
                     ├── readFromFile.groovy
                     ├── request.json
    -                └── response.json

    Further assume that your contract is as follows:

    import org.springframework.cloud.contract.spec.Contract
    +                └── response.json

    Further assume that your contract is as follows:

    Groovy DSL.  +

    import org.springframework.cloud.contract.spec.Contract
     
     Contract.make {
     	request {
    @@ -2609,11 +2958,20 @@ Contract.make {
     			contentType(textPlain())
     		}
     	}
    -}

    Further assume that the JSON files is as follows:

    request.json

    { "status" : "REQUEST" }

    response.json

    { "status" : "RESPONSE" }

    When test or stub generation takes place, the contents of the file is passed to the body -of a request or a response. That works because of the file(…​) method. The argument of -that method needs to be a file with location relative to the folder in which the contract -lays.

    8.2.5 HTTP Top-Level Elements

    The following methods can be called in the top-level closure of a contract definition. -request and response are mandatory. priority is optional.

    org.springframework.cloud.contract.spec.Contract.make {
    +}

    +

    YAML.  +

    request:
    +  method: GET
    +  url: /foo
    +  bodyFromFile: request.json
    +response:
    +  status: 200
    +  bodyFromFile: response.json

    +

    Further assume that the JSON files is as follows:

    request.json

    { "status" : "REQUEST" }

    response.json

    { "status" : "RESPONSE" }

    When test or stub generation takes place, the contents of the file is passed to the body +of a request or a response. The name of the file needs to be a file with location +relative to the folder in which the contract lays.

    8.2.5 HTTP Top-Level Elements

    The following methods can be called in the top-level closure of a contract definition. +request and response are mandatory. priority is optional.

    Groovy DSL.  +

    org.springframework.cloud.contract.spec.Contract.make {
     	// Definition of HTTP request part of the contract
     	// (this can be a valid request or invalid depending
     	// on type of contract being specified).
    @@ -2632,8 +2990,18 @@ lays.

    // Contract priority, which can be used for overriding // contracts (1 is highest). Priority is optional. priority 1 -}

    8.3 Request

    The HTTP protocol requires only method and address to be specified in a request. The -same information is mandatory in request definition of the Contract.

    org.springframework.cloud.contract.spec.Contract.make {
    +}

    +

    YAML.  +

    priority: 8
    +request:
    +...
    +response:
    +...

    +

    [Important]Important

    If you want to make your contract have a higher value of priority +you need to pass a lower number to the priority tag / method. E.g. priority with +value 5 has higher priority than priority with value 10.

    8.3 Request

    The HTTP protocol requires only method and url to be specified in a request. The +same information is mandatory in request definition of the Contract.

    Groovy DSL.  +

    org.springframework.cloud.contract.spec.Contract.make {
     	request {
     		// HTTP request method (GET/POST/PUT/DELETE).
     		method 'GET'
    @@ -2645,8 +3013,13 @@ same information is mandatory in request definition of the Contract.

    //...
     	}
    -}

    It is possible to specify an absolute rather than relative url, but using urlPath is -the recommended way, as doing so makes the tests host-independent.

    org.springframework.cloud.contract.spec.Contract.make {
    +}

    +

    YAML.  +

    method: PUT
    +url: /foo

    +

    It is possible to specify an absolute rather than relative url, but using urlPath is +the recommended way, as doing so makes the tests host-independent.

    Groovy DSL.  +

    org.springframework.cloud.contract.spec.Contract.make {
     	request {
     		method 'GET'
     
    @@ -2657,8 +3030,13 @@ the recommended way, as doing so makes the tests ho
     	response {
     		//...
     	}
    -}

    request may contain query parameters, which are specified in a closure nested in a -call to urlPath or url.

    org.springframework.cloud.contract.spec.Contract.make {
    +}

    +

    YAML.  +

    request:
    +  method: PUT
    +  urlPath: /foo

    +

    request may contain query parameters.

    Groovy DSL.  +

    org.springframework.cloud.contract.spec.Contract.make {
     	request {
     		//...
     
    @@ -2698,7 +3076,50 @@ call to urlPath or url
     	response {
     		//...
     	}
    -}

    request may contain additional request headers, as shown in the following example:

    org.springframework.cloud.contract.spec.Contract.make {
    +}

    +

    YAML.  +

    request:
    +...
    +  queryParameters:
    +    a: b
    +    b: c
    +  headers:
    +    foo: bar
    +    fooReq: baz
    +  body:
    +    foo: bar
    +  matchers:
    +    body:
    +      - path: $.foo
    +        type: by_regex
    +        value: bar
    +    headers:
    +      - key: foo
    +        regex: bar
    +response:
    +  status: 200
    +  headers:
    +    foo2: bar
    +    foo3: foo33
    +    fooRes: baz
    +  body:
    +    foo2: bar
    +    foo3: baz
    +  matchers:
    +    body:
    +      - path: $.foo2
    +        type: by_regex
    +        value: bar
    +      - path: $.foo3
    +        type: by_command
    +        value: executeMe($it)
    +    headers:
    +      - key: foo2
    +        regex: bar
    +      - key: foo3
    +        command: andMeToo($it)

    +

    request may contain additional request headers, as shown in the following example:

    Groovy DSL.  +

    org.springframework.cloud.contract.spec.Contract.make {
     	request {
     		//...
     
    @@ -2715,7 +3136,15 @@ call to urlPath or url
     	response {
     		//...
     	}
    -}

    request may contain a request body, as shown in the following example:

    org.springframework.cloud.contract.spec.Contract.make {
    +}

    +

    YAML.  +

    request:
    +...
    +headers:
    +  foo: bar
    +  fooReq: baz

    +

    request may contain a request body:

    Groovy DSL.  +

    org.springframework.cloud.contract.spec.Contract.make {
     	request {
     		//...
     
    @@ -2727,8 +3156,15 @@ call to urlPath or url
     	response {
     		//...
     	}
    -}

    request may contain multipart elements. To include multipart elements, call the -multipart() method, as shown in the following example

    org.springframework.cloud.contract.spec.Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make {
    +}

    +

    YAML.  +

    request:
    +...
    +body:
    +  foo: bar

    +

    request may contain multipart elements. To include multipart elements, use the +multipart method/section, as shown in the following examples

    Groovy DSL.  +

    org.springframework.cloud.contract.spec.Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make {
     	request {
     		method "PUT"
     		url "/multipart"
    @@ -2751,11 +3187,49 @@ call to urlPath or url
     	response {
     		status 200
     	}
    -}

    In the preceding example, we define parameters in either of two ways:

    • Directly, by using the map notation, where the value can be a dynamic property (such as +}

    +

    YAML.  +

    request:
    +  method: PUT
    +  url: /multipart
    +  headers:
    +    Content-Type: multipart/form-data;boundary=AaB03x
    +  multipart:
    +    params:
    +    # key (parameter name), value (parameter value) pair
    +      formParameter: '"formParameterValue"'
    +      someBooleanParameter: true
    +    named:
    +      - paramName: file
    +        fileName: filename.csv
    +        fileContent: file content
    +  matchers:
    +    multipart:
    +      params:
    +        - key: formParameter
    +          regex: ".+"
    +        - key: someBooleanParameter
    +          predefined: any_boolean
    +      named:
    +        - paramName: file
    +          fileName:
    +            predefined: non_empty
    +          fileContent:
    +            predefined: non_empty
    +response:
    +  status: 200

    +

    In the preceding example, we define parameters in either of two ways:

    Groovy DSL

    • Directly, by using the map notation, where the value can be a dynamic property (such as formParameter: $(consumer(…​), producer(…​))).
    • By using the named(…​) method that lets you set a named parameter. A named parameter can set a name and content. You can call it either via a method with two arguments, such as named("fileName", "fileContent"), or via a map notation, such as -named(name: "fileName", content: "fileContent").

    From this contract, the generated test is as follows:

    // given:
    +named(name: "fileName", content: "fileContent").

    YAML

    • The multipart parameters are set via multipart.params section
    • The named parameters (the fileName and fileContent for a given parameter name) +can be set via the multipart.named section. That section contains +the paramName (name of the parameter), fileName (name of the file), +fileContent (content of the file) fields
    • The dynamic bits can be set via the matchers.multipart section

      • for parameters use the params section that can accept +regex or a predefined regular expression
      • for named params use the named section where first you +define the parameter name via paramName and then you can pass the +parametrization of either fileName or fileContent via +regex or a predefined regular expression

    From this contract, the generated test is as follows:

    // given:
      MockMvcRequestSpecification request = given()
        .header("Content-Type", "multipart/form-data;boundary=AaB03x")
        .param("formParameter", "\"formParameterValue\"")
    @@ -2791,7 +3265,8 @@ such as named("fileName", "fileContent"), or via a
       }
     }
     	'''

    8.4 Response

    The response must contain an HTTP status code and may contain other information. The -following code shows an example:

    org.springframework.cloud.contract.spec.Contract.make {
    +following code shows an example:

    Groovy DSL.  +

    org.springframework.cloud.contract.spec.Contract.make {
     	request {
     		//...
     	}
    @@ -2800,12 +3275,18 @@ following code shows an example:

    org.springframew
     		// in response to request specified above.
     		status 200
     	}
    -}

    Besides status, the response may contain headers and a body, both of which are +}

    +

    YAML.  +

    response:
    +...
    +status: 200

    +

    Besides status, the response may contain headers and a body, both of which are specified the same way as in the request (see the previous paragraph).

    8.5 Dynamic properties

    The contract can contain some dynamic properties: timestamps, IDs, and so on. You do not want to force the consumers to stub their clocks to always return the same value of time -so that it gets matched by the stub. You can provide the dynamic parts in your contracts +so that it gets matched by the stub.

    For Groovy DSL you can provide the dynamic parts in your contracts in two ways: pass them directly in the body or set them in separate sections called -testMatchers and stubMatchers.

    8.5.1 Dynamic properties inside the body

    You can set the properties inside the body either with the value method or, if you use +testMatchers and stubMatchers.

    For YAML you can only use the matchers section.

    8.5.1 Dynamic properties inside the body

    [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 set the properties inside the body either with the value method or, if you use the Groovy map notation, with $(). The following example shows how to set dynamic properties with the value method:

    value(consumer(...), producer(...))
     value(c(...), p(...))
    @@ -2814,7 +3295,8 @@ value(client(...), server(...))

    The following example shows how to set d $(c(...), p(...)) $(stub(...), test(...)) $(client(...), server(...))

    Both approaches work equally well. stub and client methods are aliases over the consumer -method. Subsequent sections take a closer look at what you can do with those values.

    8.5.2 Regular expressions

    You can use regular expressions to write your requests in Contract DSL. Doing so is +method. Subsequent sections take a closer look at what you can do with those values.

    8.5.2 Regular expressions

    [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 use regular expressions to write your requests in Contract DSL. Doing so is particularly useful when you want to indicate that a given response should be provided for requests that follow a given pattern. Also, you can use regular expressions when you 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 {
    @@ -2960,7 +3442,8 @@ Pattern nonBlank() {
     				message: "User not found by email = [${value(producer(regex(email())), consumer('not.existing@user.com'))}]"
     		)
     	}
    -}

    8.5.3 Passing Optional Parameters

    It is possible to provide optional parameters in your contract. However, you can provide +}

    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
     	request {
    @@ -3003,29 +3486,30 @@ expression that must be present 0 or more times.

    If you use Spock for, the """

    The following stub would also be generated:

    '''
     {
       "request" : {
    -    "url" : "/users/password",
    -    "method" : "POST",
    -    "bodyPatterns" : [ {
    -      "matchesJsonPath" : "$[?(@.['email'] =~ /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,6})?/)]"
    -    }, {
    -      "matchesJsonPath" : "$[?(@.['callback_url'] =~ /((http[s]?|ftp):\\\\/)\\\\/?([^:\\\\/\\\\s]+)(:[0-9]{1,5})?/)]"
    -    } ],
    -    "headers" : {
    -      "Content-Type" : {
    -        "equalTo" : "application/json"
    -      }
    -    }
    +	"url" : "/users/password",
    +	"method" : "POST",
    +	"bodyPatterns" : [ {
    +	  "matchesJsonPath" : "$[?(@.['email'] =~ /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,6})?/)]"
    +	}, {
    +	  "matchesJsonPath" : "$[?(@.['callback_url'] =~ /((http[s]?|ftp):\\\\/)\\\\/?([^:\\\\/\\\\s]+)(:[0-9]{1,5})?/)]"
    +	} ],
    +	"headers" : {
    +	  "Content-Type" : {
    +		"equalTo" : "application/json"
    +	  }
    +	}
       },
       "response" : {
    -    "status" : 404,
    -    "body" : "{\\"code\\":\\"123123\\",\\"message\\":\\"User not found by email == [not.existing@user.com]\\"}",
    -    "headers" : {
    -      "Content-Type" : "application/json"
    -    }
    +	"status" : 404,
    +	"body" : "{\\"code\\":\\"123123\\",\\"message\\":\\"User not found by email == [not.existing@user.com]\\"}",
    +	"headers" : {
    +	  "Content-Type" : "application/json"
    +	}
       },
       "priority" : 1
     }
    -'''

    8.5.4 Executing Custom Methods on the Server Side

    You can define a method call that executes on the server side during the test. Such a +'''

    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 method can be added to the class defined as "baseClassForTests" in the configuration. The following code shows an example of the contract portion of the test case:

    org.springframework.cloud.contract.spec.Contract.make {
     	request {
    @@ -3089,11 +3573,17 @@ It should resemble the following code:

    // 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 -request in your response. To do so, you can use the fromRequest() method, which lets +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 given name.
    • fromRequest().path(): Returns the full path.
    • fromRequest().path(int index): Returns the nth path element.
    • fromRequest().header(String key): Returns the first header with a given name.
    • fromRequest().header(String key, int index): Returns the nth header with a given name.
    • fromRequest().body(): Returns the full request body.
    • fromRequest().body(String jsonPath): Returns the element from the request that -matches the JSON Path.

    Consider the following contract:

    Contract contractDsl = Contract.make {
    +matches the JSON Path.

    If you’re using the YAML contract definition you have to use the +Handlebars {{{ }}} notation with custom, Spring Cloud Contract + functions to achieve this.

    • {{{ request.url }}}: Returns the request URL and query parameters.
    • {{{ request.query.key.[index] }}}: Returns the nth query parameter with a given name. +E.g. for key foo, first entry {{{ request.query.foo.[0] }}}
    • {{{ request.path }}}: Returns the full path.
    • {{{ request.path.[index] }}}: Returns the nth path element. E.g. +for first entry `{{{ request.path.[0] }}}
    • {{{ request.headers.key }}}: Returns the first header with a given name.
    • {{{ request.headers.key.[index] }}}: Returns the nth header with a given name.
    • {{{ request.body }}}: Returns the full request body.
    • {{{ jsonpath this 'your.json.path' }}}: Returns the element from the request that +matches the JSON Path. E.g. for json path $.foo - {{{ jsonpath this '$.foo' }}}

    Consider the following contract:

    Groovy DSL.  +

    Contract contractDsl = Contract.make {
     	request {
     		method 'GET'
     		url('/api/v1/xxxx') {
    @@ -3127,7 +3617,39 @@ matches the JSON Path.

    Consider the following contract:

    "Bla bla ${fromRequest().body('$.foo')} bla bla" ) } -}

    Running a JUnit test generation leads to a test that resembles the following example:

    // given:
    +}

    +

    YAML.  +

    request:
    +  method: GET
    +  url: /api/v1/xxxx
    +  queryParameters:
    +    foo:
    +      - bar
    +      - bar2
    +  headers:
    +    Authorization:
    +      - secret
    +      - secret2
    +  body:
    +    foo: bar
    +    baz: 5
    +response:
    +  status: 200
    +  headers:
    +    Authorization: "foo {{{ request.headers.Authorization.0 }}} bar"
    +  body:
    +    url: "{{{ request.url }}}"
    +    path: "{{{ request.path }}}"
    +    pathIndex: "{{{ request.path.1 }}}"
    +    param: "{{{ request.query.foo }}}"
    +    paramIndex: "{{{ request.query.foo.1 }}}"
    +    authorization: "{{{ request.headers.Authorization.0 }}}"
    +    authorization2: "{{{ request.headers.Authorization.1 }}"
    +    fullBody: "{{{ request.body }}}"
    +    responseFoo: "{{{ jsonpath this '$.foo' }}}"
    +    responseBaz: "{{{ jsonpath this '$.baz' }}}"
    +    responseBaz2: "Bla bla {{{ jsonpath this '$.foo' }}} bla bla"

    +

    Running a JUnit test generation leads to a test that resembles the following example:

    // given:
      MockMvcRequestSpecification request = given()
        .header("Authorization", "secret")
        .header("Authorization", "secret2")
    @@ -3230,12 +3752,12 @@ org.springframework.cloud.contract.stubrunner.provider.wiremock.TestWireMockExte
     	}
     }

    [Important]Important

    Remember to override the applyGlobally() method and set it to false if you -want the transformation to be applied only for a mapping that explicitly requires it.

    8.5.7 Dynamic Properties in the Matchers Sections

    If you work with Pact, the following discussion may seem familiar. +want the transformation to be applied only for a mapping that explicitly requires it.

    8.5.7 Dynamic Properties in the Matchers Sections

    If you work with Pact, the following discussion may seem familiar. Quite a few users are used to having a separation between the body and setting the dynamic parts of a contract.

    You can use two separate sections:

    • stubMatchers, which lets you define the dynamic values that should end up in a stub. You can set it in the request or inputMessage part of your contract.
    • testMatchers, which is present in the response or outputMessage side of the contract.

    Currently, Spring Cloud Contract Verifier supports only JSON Path-based matchers with the -following matching possibilities:

    • For stubMatchers:

      • byEquality(): The value taken from the response via the provided JSON Path must be +following matching possibilities:

        Groovy DSL

        • For stubMatchers:

          • byEquality(): The value taken from the response via the provided JSON Path must be equal to the value provided in the contract.
          • byRegex(…​): The value taken from the response via the provided JSON Path must match the regex.
          • byDate(): The value taken from the response via the provided JSON Path must match the regex for an ISO Date value.
          • byTimestamp(): The value taken from the response via the provided JSON Path must @@ -3253,7 +3775,15 @@ unflattened collection, use a custom method with the byCom passed as an input to the custom method that you provide. For example, byCommand('foo($it)') results in calling a foo method to which the value matching the JSON Path gets passed. The type of the object read from the JSON can be one of the -following, depending on the JSON path:

            • String: If you point to a String value.
            • JSONArray: If you point to a List.
            • Map: If you point to a Map.
            • Number: If you point to Integer, Double, or other kind of number.
            • Boolean: If you point to a Boolean.

        Consider the following example:

        Contract contractDsl = Contract.make {
        +following, depending on the JSON path:

        • String: If you point to a String value.
        • JSONArray: If you point to a List.
        • Map: If you point to a Map.
        • Number: If you point to Integer, Double, or other kind of number.
        • Boolean: If you point to a Boolean.

    YAML. Please read the Groovy section for detailed explanation of +what the types mean

    For YAML the structure of a matcher looks like this

    - path: $.foo
    +  type: by_regex
    +  value: bar

    Or if you want to use one of the predefined regular expressions +[only_alpha_unicode, number, any_boolean, ip_address, hostname, +email, url, uuid, iso_date, iso_date_time, iso_time, iso_8601_with_offset, non_empty, non_blank]:

    - path: $.foo
    +  type: by_regex
    +  predefined: only_alpha_unicode

    Below you can find the allowed list of `type`s.

    • For stubMatchers:

      • by_equality
      • by_regex
      • by_date
      • by_timestamp
      • by_time
    • For testMatchers:

      • by_equality
      • by_regex
      • by_date
      • by_timestamp
      • by_time
      • by_type

        • there are 2 additional fields accepted: minOccurrence and maxOccurrence.
      • by_command

    Consider the following example:

    Groovy DSL.  +

    Contract contractDsl = Contract.make {
     	request {
     		method 'GET'
     		urlPath '/get'
    @@ -3359,7 +3889,133 @@ following, depending on the JSON path:

      request: + method: GET + urlPath: /get + body: + duck: 123 + alpha: "abc" + number: 123 + aBoolean: true + date: "2017-01-01" + dateTime: "2017-01-01T01:23:45" + time: "01:02:34" + valueWithoutAMatcher: "foo" + valueWithTypeMatch: "string" + key: + "complex.key": 'foo' + matchers: + headers: + - key: Content-Type + regex: "application/json.*" + body: + - path: $.duck + type: by_regex + value: "[0-9]{3}" + - path: $.duck + type: by_equality + - path: $.alpha + type: by_regex + predefined: only_alpha_unicode + - path: $.alpha + type: by_equality + - path: $.number + type: by_regex + predefined: number + - path: $.aBoolean + type: by_regex + predefined: any_boolean + - path: $.date + type: by_date + - path: $.dateTime + type: by_timestamp + - path: $.time + type: by_time + - path: "$.['key'].['complex.key']" + type: by_equality + headers: + Content-Type: application/json +response: + status: 200 + body: + duck: 123 + alpha: "abc" + number: 123 + aBoolean: true + date: "2017-01-01" + dateTime: "2017-01-01T01:23:45" + time: "01:02:34" + valueWithoutAMatcher: "foo" + valueWithTypeMatch: "string" + valueWithMin: + - 1 + - 2 + - 3 + valueWithMax: + - 1 + - 2 + - 3 + valueWithMinMax: + - 1 + - 2 + - 3 + valueWithMinEmpty: [] + valueWithMaxEmpty: [] + key: + 'complex.key' : 'foo' + matchers: + headers: + - key: Content-Type + regex: "application/json.*" + body: + - path: $.duck + type: by_regex + value: "[0-9]{3}" + - path: $.duck + type: by_equality + - path: $.alpha + type: by_regex + predefined: only_alpha_unicode + - path: $.alpha + type: by_equality + - path: $.number + type: by_regex + predefined: number + - path: $.aBoolean + type: by_regex + predefined: any_boolean + - path: $.date + type: by_date + - path: $.dateTime + type: by_timestamp + - path: $.time + type: by_time + - path: $.valueWithTypeMatch + type: by_type + - path: $.valueWithMin + type: by_type + minOccurrence: 1 + - path: $.valueWithMax + type: by_type + maxOccurrence: 3 + - path: $.valueWithMinMax + type: by_type + minOccurrence: 1 + maxOccurrence: 3 + - path: $.valueWithMinEmpty + type: by_type + minOccurrence: 0 + - path: $.valueWithMaxEmpty + type: by_type + maxOccurrence: 0 + - path: $.duck + type: by_command + value: assertThatValueIsANumber($it) + headers: + Content-Type: application/json

    +

    In the preceding example, you can see the dynamic portions of the contract in the matchers sections. For the request part, you can see that, for all fields but valueWithoutAMatcher, the values of the regular expressions that the stub should contain are explicitly set. For the valueWithoutAMatcher, the verification takes place @@ -3415,51 +4071,51 @@ statically imported to your tests. Notice that the byComma the method name and passed the proper JSON path as a parameter to it.

    The resulting WireMock stub is in the following example:

    				'''
     {
       "request" : {
    -    "urlPath" : "/get",
    -    "method" : "POST",
    -    "headers" : {
    -      "Content-Type" : {
    -        "matches" : "application/json.*"
    -      }
    -    },
    -    "bodyPatterns" : [ {
    -      "matchesJsonPath" : "$[?(@.['valueWithoutAMatcher'] == 'foo')]"
    -    }, {
    -      "matchesJsonPath" : "$[?(@.['valueWithTypeMatch'] == 'string')]"
    -    }, {
    -      "matchesJsonPath" : "$.['list'].['some'].['nested'][?(@.['anothervalue'] == 4)]"
    -    }, {
    -      "matchesJsonPath" : "$.['list'].['someother'].['nested'][?(@.['anothervalue'] == 4)]"
    -    }, {
    -      "matchesJsonPath" : "$.['list'].['someother'].['nested'][?(@.['json'] == 'with value')]"
    -    }, {
    -      "matchesJsonPath" : "$[?(@.duck =~ /([0-9]{3})/)]"
    -    }, {
    -      "matchesJsonPath" : "$[?(@.duck == 123)]"
    -    }, {
    -      "matchesJsonPath" : "$[?(@.alpha =~ /([\\\\p{L}]*)/)]"
    -    }, {
    -      "matchesJsonPath" : "$[?(@.alpha == 'abc')]"
    -    }, {
    -      "matchesJsonPath" : "$[?(@.number =~ /(-?(\\\\d*\\\\.\\\\d+|\\\\d+))/)]"
    -    }, {
    -      "matchesJsonPath" : "$[?(@.aBoolean =~ /((true|false))/)]"
    -    }, {
    -      "matchesJsonPath" : "$[?(@.date =~ /((\\\\d\\\\d\\\\d\\\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01]))/)]"
    -    }, {
    -      "matchesJsonPath" : "$[?(@.dateTime =~ /(([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]))/)]"
    -    }, {
    -      "matchesJsonPath" : "$[?(@.time =~ /((2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9]))/)]"
    -    }, {
    -      "matchesJsonPath" : "$.list.some.nested[?(@.json =~ /(.*)/)]"
    -    } ]
    +	"urlPath" : "/get",
    +	"method" : "POST",
    +	"headers" : {
    +	  "Content-Type" : {
    +		"matches" : "application/json.*"
    +	  }
    +	},
    +	"bodyPatterns" : [ {
    +	  "matchesJsonPath" : "$[?(@.['valueWithoutAMatcher'] == 'foo')]"
    +	}, {
    +	  "matchesJsonPath" : "$[?(@.['valueWithTypeMatch'] == 'string')]"
    +	}, {
    +	  "matchesJsonPath" : "$.['list'].['some'].['nested'][?(@.['anothervalue'] == 4)]"
    +	}, {
    +	  "matchesJsonPath" : "$.['list'].['someother'].['nested'][?(@.['anothervalue'] == 4)]"
    +	}, {
    +	  "matchesJsonPath" : "$.['list'].['someother'].['nested'][?(@.['json'] == 'with value')]"
    +	}, {
    +	  "matchesJsonPath" : "$[?(@.duck =~ /([0-9]{3})/)]"
    +	}, {
    +	  "matchesJsonPath" : "$[?(@.duck == 123)]"
    +	}, {
    +	  "matchesJsonPath" : "$[?(@.alpha =~ /([\\\\p{L}]*)/)]"
    +	}, {
    +	  "matchesJsonPath" : "$[?(@.alpha == 'abc')]"
    +	}, {
    +	  "matchesJsonPath" : "$[?(@.number =~ /(-?(\\\\d*\\\\.\\\\d+|\\\\d+))/)]"
    +	}, {
    +	  "matchesJsonPath" : "$[?(@.aBoolean =~ /((true|false))/)]"
    +	}, {
    +	  "matchesJsonPath" : "$[?(@.date =~ /((\\\\d\\\\d\\\\d\\\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01]))/)]"
    +	}, {
    +	  "matchesJsonPath" : "$[?(@.dateTime =~ /(([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]))/)]"
    +	}, {
    +	  "matchesJsonPath" : "$[?(@.time =~ /((2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9]))/)]"
    +	}, {
    +	  "matchesJsonPath" : "$.list.some.nested[?(@.json =~ /(.*)/)]"
    +	} ]
       },
       "response" : {
    -    "status" : 200,
    -    "body" : "{\\"date\\":\\"2017-01-01\\",\\"dateTime\\":\\"2017-01-01T01:23:45\\",\\"number\\":123,\\"aBoolean\\":true,\\"duck\\":123,\\"alpha\\":\\"abc\\",\\"valueWithMin\\":[1,2,3],\\"time\\":\\"01:02:34\\",\\"valueWithTypeMatch\\":\\"string\\",\\"valueWithMax\\":[1,2,3],\\"valueWithMinMax\\":[1,2,3],\\"valueWithoutAMatcher\\":\\"foo\\"}",
    -    "headers" : {
    -      "Content-Type" : "application/json"
    -    }
    +	"status" : 200,
    +	"body" : "{\\"date\\":\\"2017-01-01\\",\\"dateTime\\":\\"2017-01-01T01:23:45\\",\\"number\\":123,\\"aBoolean\\":true,\\"duck\\":123,\\"alpha\\":\\"abc\\",\\"valueWithMin\\":[1,2,3],\\"time\\":\\"01:02:34\\",\\"valueWithTypeMatch\\":\\"string\\",\\"valueWithMax\\":[1,2,3],\\"valueWithMinMax\\":[1,2,3],\\"valueWithoutAMatcher\\":\\"foo\\"}",
    +	"headers" : {
    +	  "Content-Type" : "application/json"
    +	}
       }
     }
     '''
    [Important]Important

    If you use a matcher, then the part of the request aned response that the @@ -3528,7 +4184,8 @@ content type set. Otherwise, the default of application/oc assertThatJson(parsedJson).field("['property1']").isEqualTo("a"); '''

    8.7 Async Support

    If you’re using asynchronous communication on the server side (your controllers are returning Callable, DeferredResult, and so on), then, inside your contract, you must -provide a sync() method in the response section. The following code shows an example:

    org.springframework.cloud.contract.spec.Contract.make {
    +provide a sync() method in the response section. The following code shows an example:

    Groovy DSL.  +

    org.springframework.cloud.contract.spec.Contract.make {
         request {
             method GET()
             url '/get'
    @@ -3538,7 +4195,11 @@ provide a sync() method in the 'Passed'
             async()
         }
    -}

    8.8 Working with Context Paths

    Spring Cloud Contract supports context paths.

    [Important]Important

    The only change needed to fully support context paths is the switch on the +}

    +

    YAML.  +

    response:
    +    async: true

    +

    8.8 Working with Context Paths

    Spring Cloud Contract supports context paths.

    [Important]Important

    The only change needed to fully support context paths is the switch on the PRODUCER side. Also, the autogenerated tests must use EXPLICIT mode. The consumer side remains untouched. In order for the generated test to pass, you must use EXPLICIT mode.

    Maven.  @@ -3584,7 +4245,8 @@ socket.

    Consider the following contract:

    or
     context path included (for example, /my-context-path/url).
  • Your contracts reflect that you have a context path. Your generated stubs also have that information (for example, in the stubs, you have to call /my-context-path/url).
  • 8.9 Messaging Top-Level Elements

    The DSL for messaging looks a little bit different than the one that focuses on HTTP. The following sections explain the differences:

    8.9.1 Output Triggered by a Method

    The output message can be triggered by calling a method (such as a Scheduler when a was -started and a message was sent), as shown in the following example:

    def dsl = Contract.make {
    +started and a message was sent), as shown in the following example:

    Groovy DSL.  +

    def dsl = Contract.make {
     	// Human readable description
     	description 'Some description'
     	// Label by means of which the output message can be triggered
    @@ -3605,11 +4267,31 @@ started and a message was sent), as shown in the following example:

    'BOOK-NAME', 'foo')
     		}
     	}
    -}

    In the previous example case, the output message is sent to output if a method called +}

    +

    YAML.  +

    # Human readable description
    +description: Some description
    +# Label by means of which the output message can be triggered
    +label: some_label
    +input:
    +  # the contract will be triggered by a method
    +  triggeredBy: bookReturnedTriggered()
    +# output message of the contract
    +outputMessage:
    +  # destination to which the output message will be sent
    +  sentTo: output
    +  # the body of the output message
    +  body:
    +    bookName: foo
    +  # the headers of the output message
    +  headers:
    +    BOOK-NAME: foo

    +

    In the previous example case, the output message is sent to output if a method called bookReturnedTriggered is executed. On the message publisher’s side, we generate a test that calls that method to trigger the message. On the consumer side, you can use the some_label to trigger the message.

    8.9.2 Output Triggered by a Message

    The output message can be triggered by receiving a message, as shown in the following -example:

    def dsl = Contract.make {
    +example:

    Groovy DSL.  +

    def dsl = Contract.make {
     	description 'Some Description'
     	label 'some_label'
     	// input is a message
    @@ -3634,11 +4316,36 @@ example:

    def dsl = Contract.make {
     			header('BOOK-NAME', 'foo')
     		}
     	}
    -}

    In the preceding example, the output message is sent to output if a proper message is +}

    +

    YAML.  +

    # Human readable description
    +description: Some description
    +# Label by means of which the output message can be triggered
    +label: some_label
    +# input is a message
    +input:
    +  messageFrom: input
    +  # has the following body
    +  messageBody:
    +    bookName: 'foo'
    +  # and the following headers
    +  messageHeaders:
    +    sample: 'header'
    +# output message of the contract
    +outputMessage:
    +  # destination to which the output message will be sent
    +  sentTo: output
    +  # the body of the output message
    +  body:
    +    bookName: foo
    +  # the headers of the output message
    +  headers:
    +    BOOK-NAME: foo

    +

    In the preceding example, the output message is sent to output if a proper message is received on the input destination. On the message publisher’s side, the engine generates a test that sends the input message to the defined destination. On the consumer side, you can either send a message to the input destination or use a label -(some_label in the example) to trigger the message.

    8.9.3 Consumer/Producer

    In HTTP, you have a notion of client/stub and `server/test notation. You can also +(some_label in the example) to trigger the message.

    8.9.3 Consumer/Producer

    [Important]Important

    This section is valid only for Groovy DSL.

    In HTTP, you have a notion of client/stub and `server/test notation. You can also use those paradigms in messaging. In addition, Spring Cloud Contract Verifier also provides the consumer and producer methods, as presented in the following example (note that you can use either $ or value methods to provide consumer and producer @@ -3659,11 +4366,12 @@ parts):

    Contract.make {
     				bookName: 'foo'
     		])
     	}
    -}

    8.9.4 Common

    In the input {} or outputMessage {} section you can call assertThat with the name +}

    8.9.4 Common

    In the input or outputMessage section you can call assertThat with the name of a method (e.g. assertThatMessageIsOnTheQueue()) that you have defined in the -base class or in a static import. Spring Cloud Pipelines will execute that method -in the genertaed test.

    8.10 Multiple Contracts in One File

    You can define multiple contracts in one file. Such a contract might resemble the -following example:

    import org.springframework.cloud.contract.spec.Contract
    +base class or in a static import. Spring Cloud Contract will execute that method
    +in the generated test.

    8.10 Multiple Contracts in One File

    You can define multiple contracts in one file. Such a contract might resemble the +following example:

    Groovy DSL.  +

    import org.springframework.cloud.contract.spec.Contract
     
     [
             Contract.make {
    @@ -3685,7 +4393,23 @@ following example:

    200
                 }
             }
    -]

    In the preceding example, one contract has the name field and the other does not. This +]

    +

    YAML.  +

    ---
    +name: should post a user
    +request:
    +  method: POST
    +  url: /users/1
    +response:
    +  status: 200
    +
    +---
    +request:
    +  method: POST
    +  url: /users/2
    +response:
    +  status: 200

    +

    In the preceding example, one contract has the name field and the other does not. This leads to generation of two tests that look more or less like this:

    package org.springframework.cloud.contract.verifier.tests.com.hello;
     
     import com.example.TestBase;
    @@ -3734,7 +4458,7 @@ index of the contract in the list.

    The generated stubs is shown in the fol 1_WithList.json

    As you can see, the first file got the name parameter from the contract. The second got the name of the contract file (WithList.groovy) prefixed with the index (in this case, the contract had an index of 1 in the list of contracts in the file).

    [Tip]Tip

    As you can see, it iss much better if you name your contracts because doing so makes -your tests far more meaningful.

    9. Customization

    You can customize the Spring Cloud Contract Verifier by extending the DSL, as shown in +your tests far more meaningful.

    9. Customization

    [Important]Important

    This section is valid only for Groovy DSL

    You can customize the Spring Cloud Contract Verifier by extending the DSL, as shown in the remainder of this section.

    9.1 Extending the DSL

    You can provide your own functions to the DSL. The key requirement for this feature is to maintain the static compatibility. Later in this document, you can see examples of:

    • Creating a JAR with reusable classes.
    • Referencing of these classes in the DSLs.

    You can find the full example here.

    9.1.1 Common JAR

    The following examples show three classes that can be reused in the DSLs.

    PatternUtils contains functions used by both the consumer and the producer.

    package com.example;
    @@ -3953,19 +4677,7 @@ such as YAML, RAML or PACT. In those cases, you still want to benefit from the a
     generation of tests and stubs. You can add your own implementation for generating both
     tests and stubs. Also, you can customize the way tests are generated (for example, you
     can generate tests for other languages) and the way stubs are generated (for example, you
    -can generate stubs for other HTTP server implementations).

    10.1 Custom Contract Converter

    Assume that your contract is written in a YAML file as follows:

    request:
    -  url: /foo
    -  method: PUT
    -  headers:
    -    foo: bar
    -  body:
    -    foo: bar
    -response:
    -  status: 200
    -  headers:
    -    foo2: bar
    -  body:
    -    foo2: bar

    The ContractConverter interface lets you register your own implementation of a contract +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
     
     /**
    @@ -4006,87 +4718,8 @@ structure converter. The following code listing shows the 
     }

    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 /META-INF/spring.factories file in which you provide the fully qualified name of your -implementation.

    The following example shows a typical spring.factories file:

    # Converters
    -org.springframework.cloud.contract.spec.ContractConverter=\
    -org.springframework.cloud.contract.verifier.converter.YamlContractConverter
    -
    -# tag::extension[]
    -org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockExtensions=\
    -org.springframework.cloud.contract.verifier.dsl.wiremock.TestWireMockExtensions
    -# end::extension[]

    The following example shows a typical YAML implementation that matches the preceding -example:

    package org.springframework.cloud.contract.verifier.converter
    -
    -import java.nio.file.Files
    -
    -import groovy.transform.CompileStatic
    -import org.springframework.cloud.contract.spec.Contract
    -import org.springframework.cloud.contract.spec.ContractConverter
    -import org.springframework.cloud.contract.spec.internal.Headers
    -import org.yaml.snakeyaml.Yaml
    -
    -/**
    - * Simple converter from and to a {@link YamlContract} to a collection of {@link Contract}
    - */
    -@CompileStatic
    -class YamlContractConverter implements ContractConverter<List<YamlContract>> {
    -
    -	@Override
    -	public boolean isAccepted(File file) {
    -		String name = file.getName()
    -		return name.endsWith(".yml") || name.endsWith(".yaml")
    -	}
    -
    -	@Override
    -	public Collection<Contract> convertFrom(File file) {
    -		try {
    -			YamlContract yamlContract = new Yaml().loadAs(
    -					Files.newInputStream(file.toPath()), YamlContract.class)
    -			return [Contract.make {
    -				request {
    -					method(yamlContract?.request?.method)
    -					url(yamlContract?.request?.url)
    -					headers {
    -						yamlContract?.request?.headers?.each { String key, Object value ->
    -							header(key, value)
    -						}
    -					}
    -					body(yamlContract?.request?.body)
    -				}
    -				response {
    -					status(yamlContract?.response?.status)
    -					headers {
    -						yamlContract?.response?.headers?.each { String key, Object value ->
    -							header(key, value)
    -						}
    -					}
    -					body(yamlContract?.response?.body)
    -				}
    -			}]
    -		}
    -		catch (FileNotFoundException e) {
    -			throw new IllegalStateException(e)
    -		}
    -	}
    -
    -	@Override
    -	public List<YamlContract> convertTo(Collection<Contract> contracts) {
    -		return contracts.collect { Contract contract ->
    -			YamlContract yamlContract = new YamlContract()
    -			yamlContract.request.with {
    -				method = contract?.request?.method?.clientValue
    -				url = contract?.request?.url?.clientValue
    -				headers = (contract?.request?.headers as Headers)?.asStubSideMap()
    -				body = contract?.request?.body?.clientValue as Map
    -			}
    -			yamlContract.response.with {
    -				status = contract?.response?.status?.clientValue as Integer
    -				headers = (contract?.response?.headers as Headers)?.asStubSideMap()
    -				body = contract?.response?.body?.clientValue as Map
    -			}
    -			return yamlContract
    -		}
    -	}
    -}

    10.1.1 Pact Converter

    Spring Cloud Contract includes support for Pact representation of +implementation.

    The following example shows a typical spring.factories file:

    org.springframework.cloud.contract.spec.ContractConverter=\
    +org.springframework.cloud.contract.verifier.converter.YamlContractConverter

    10.1.1 Pact Converter

    Spring Cloud Contract includes support for Pact representation of contracts. Instead of using the Groovy DSL, you can use Pact files. In this section, we present how to add Pact support for your project.

    10.1.2 Pact Contract

    Consider following example of a Pact contract, which is a file under the src/test/resources/contracts folder.

    {
    @@ -4567,12 +5200,13 @@ Example:

    		

    11.7 Generating Stubs using REST Docs

    Spring REST Docs can be used to generate -documentation (for example in Asciidoctor format) for an HTTP API with Spring MockMvc or +documentation (for example in Asciidoctor format) for an HTTP API with Spring MockMvc +or WebTestClient or Rest Assured. At the same time that you generate documentation for your API, you can also generate WireMock stubs by using Spring Cloud Contract WireMock. To do so, write your normal REST Docs test cases and use @AutoConfigureRestDocs to have stubs be automatically generated in the REST Docs output directory. The following code shows an -example:

    @RunWith(SpringRunner.class)
    +example using MockMvc:

    @RunWith(SpringRunner.class)
     @SpringBootTest
     @AutoConfigureRestDocs(outputDir = "target/snippets")
     @AutoConfigureMockMvc
    @@ -4588,32 +5222,49 @@ example:

    "resource"));
     	}
     }

    This test generates a WireMock stub at "target/snippets/stubs/resource.json". It matches -all GET requests to the "/resource" path.

    Without any additional configuration, this tests creates a stub with a request matcher +all GET requests to the "/resource" path. The same example with WebTestClient (used +for testing Spring WebFlux applications) would look like this:

    @RunWith(SpringRunner.class)
    +@SpringBootTest
    +@AutoConfigureRestDocs(outputDir = "target/snippets")
    +@AutoConfigureWebTestClient
    +public class ApplicationTests {
    +
    +	@Autowired
    +	private WebTestClient client;
    +
    +	@Test
    +	public void contextLoads() throws Exception {
    +		client.get().uri("/resource").exchange()
    +				.expectBody(String.class).isEqualTo("Hello World")
    + 				.consumeWith(document("resource"));
    +	}
    +}

    Without any additional configuration, these tests create a stub with a request matcher for the HTTP method and all headers except "host" and "content-length". To match the request more precisely (for example, to match the body of a POST or PUT), we need to explicitly create a request matcher. Doing so has two effects:

    • Creating a stub that matches only in the way you specify.
    • Asserting that the request in the test case also matches the same conditions.

    The main entry point for this feature is WireMockRestDocs.verify(), which can be used as a substitute for the document() convenience method, as shown in the following -example:

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

    import static org.springframework.cloud.contract.wiremock.restdocs.WireMockRestDocs.verify;
    @RunWith(SpringRunner.class)
    +@SpringBootTest
    +@AutoConfigureRestDocs(outputDir = "target/snippets")
    +@AutoConfigureMockMvc
    +public class ApplicationTests {
     
    -	@Autowired
    -	private MockMvc mockMvc;
    +	@Autowired
    +	private MockMvc mockMvc;
     
    -	@Test
    -	public void contextLoads() throws Exception {
    -		mockMvc.perform(post("/resource")
    -                .content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
    +	@Test
    +	public void contextLoads() throws Exception {
    +		mockMvc.perform(post("/resource")
    +                .content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
     				.andExpect(status().isOk())
    -				.andDo(verify().jsonPath("$.id")
    -                        .stub("resource"));
    +				.andDo(verify().jsonPath("$.id")
    +                        .stub("resource"));
     	}
     }

    This contract specifies that any valid POST with an "id" field receives the response defined in this test. You can chain together calls to .jsonPath() to add additional matchers. If JSON Path is unfamiliar, The JayWay -documentation can help you get up to speed.

    Instead of the jsonPath and contentType convenience methods, you can also use the +documentation can help you get up to speed. 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
     public void contextLoads() throws Exception {
    diff --git a/spring-cloud-contract-maven-plugin/checkstyle.html b/spring-cloud-contract-maven-plugin/checkstyle.html
    index 425af2122a..fb5b0c1300 100644
    --- a/spring-cloud-contract-maven-plugin/checkstyle.html
    +++ b/spring-cloud-contract-maven-plugin/checkstyle.html
    @@ -1,13 +1,13 @@
     
     
     
       
         
         
    -    
    +    
         
         Spring Cloud Contract Maven Plugin – Checkstyle Results
         
    @@ -146,7 +146,7 @@