YAML contracts (#522)
with this change we allow the users to use YAML to define contracts fixes gh-300 gh-508 helps with #501
This commit is contained in:
committed by
GitHub
parent
b2428c5f13
commit
b745d9a7e3
166
README.adoc
166
README.adoc
@@ -130,6 +130,7 @@ Assume that you want to send a request containing the ID of a client company and
|
||||
amount it wants to borrow from us. You also want to send it to the /fraudcheck url via
|
||||
the PUT method.
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
package contracts
|
||||
@@ -191,6 +192,63 @@ From the Producer perspective, in the autogenerated producer-side test:
|
||||
*/
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
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`
|
||||
----
|
||||
|
||||
==== Client Side
|
||||
|
||||
Spring Cloud Contract generates stubs, which you can use during client-side testing.
|
||||
@@ -231,7 +289,7 @@ 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:
|
||||
The autogenerated test looks, more or less, like this:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@@ -418,7 +476,7 @@ clone it.
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
git clone https://your-git-server.com/server-side.git local-http-server-repo
|
||||
$ 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.*
|
||||
@@ -429,6 +487,7 @@ your expectations. To do so, write the following contract:
|
||||
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.
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
package contracts
|
||||
@@ -490,8 +549,66 @@ From the Producer perspective, in the autogenerated producer-side test:
|
||||
*/
|
||||
----
|
||||
|
||||
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
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
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
|
||||
@@ -565,8 +682,8 @@ stubs. You need to skip the test generation and execution. When you execute:
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
cd local-http-server-repo
|
||||
./mvnw clean install -DskipTests
|
||||
$ cd local-http-server-repo
|
||||
$ ./mvnw clean install -DskipTests
|
||||
----
|
||||
|
||||
In the logs, you see something like this:
|
||||
@@ -691,8 +808,8 @@ return new FraudCheckResult(FraudCheckStatus.OK, NO_REASON);
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
git checkout -b contract-change-pr master
|
||||
git pull https://your-git-server.com/server-side-fork.git contract-change-pr
|
||||
$ 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:
|
||||
@@ -802,8 +919,9 @@ public void validate_shouldMarkClientAsFraud() throws Exception {
|
||||
}
|
||||
----
|
||||
|
||||
As you can see, all the `producer()` parts of the Contract that were present in the
|
||||
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,
|
||||
@@ -837,9 +955,9 @@ Once you finish your work, you can deploy your change. First, merge the branch:
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
git checkout master
|
||||
git merge --no-ff contract-change-pr
|
||||
git push origin master
|
||||
$ 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
|
||||
@@ -853,8 +971,8 @@ As a developer of the Loan Issuance service (a consumer of the Fraud Detection s
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
git checkout master
|
||||
git merge --no-ff contract-change-pr
|
||||
$ git checkout master
|
||||
$ git merge --no-ff contract-change-pr
|
||||
----
|
||||
|
||||
*Work online.*
|
||||
@@ -1149,6 +1267,23 @@ Spring Boot embedded servers, and Wiremock itself has "native" support for a par
|
||||
version of Jetty (currently 9.2). To use the native Jetty, you need to add the native
|
||||
Wiremock dependencies and exclude the Spring Boot container (if there is one).
|
||||
|
||||
=== Customization of WireMock configuration
|
||||
|
||||
You can register a bean of `org.springframework.cloud.contract.wiremock.WireMockConfigurationCustomizer` type
|
||||
in order to customize the WireMock configuration (e.g. add custom transformers).
|
||||
Example:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@Bean WireMockConfigurationCustomizer optionsCustomizer() {
|
||||
return new WireMockConfigurationCustomizer() {
|
||||
@Override public void customize(WireMockConfiguration options) {
|
||||
// perform your customization here
|
||||
}
|
||||
};
|
||||
}
|
||||
----
|
||||
|
||||
=== Generating Stubs using REST Docs
|
||||
|
||||
https://projects.spring.io/spring-restdocs[Spring REST Docs] can be used to generate
|
||||
@@ -1300,12 +1435,13 @@ Consider the following test:
|
||||
.accept(MediaType.APPLICATION_PDF)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"foo\": 23 }"))
|
||||
.content("{\"foo\": 23, \"bar\" : \"baz\" }"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string("bar"))
|
||||
// first WireMock
|
||||
.andDo(WireMockRestDocs.verify()
|
||||
.jsonPath("$[?(@.foo >= 20)]")
|
||||
.jsonPath("$[?(@.bar in ['baz','bazz','bazzz'])]")
|
||||
.contentType(MediaType.valueOf("application/json"))
|
||||
.stub("shouldGrantABeerIfOldEnough"))
|
||||
// then Contract DSL documentation
|
||||
|
||||
@@ -1,33 +1,36 @@
|
||||
== Contract DSL
|
||||
|
||||
IMPORTANT: Remember that, inside the contract file, you have to provide the fully
|
||||
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: 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: Spring Cloud Contract supports defining multiple contracts in a single file.
|
||||
|
||||
The Contract is present in the `spring-cloud-contract-spec` module of the
|
||||
https://github.com/spring-cloud/spring-cloud-contract/tree/master/spring-cloud-contract-verifier[Spring
|
||||
Cloud Contract Verifier repository].
|
||||
|
||||
The following is a complete example of a contract definition:
|
||||
The following is a complete example of a Groovy contract definition:
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy[tags=dsl_example,indent=0]
|
||||
----
|
||||
|
||||
NOTE: The preceding example does not contain all the features of the DSL appear. The
|
||||
remainder of this section describes the other features.
|
||||
The following is a complete example of a YAML contract definition:
|
||||
|
||||
You can compile Contracts to WireMock stubs mapping using standalone maven command:
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract_rest.yml[indent=0]
|
||||
----
|
||||
|
||||
TIP: You can compile contracts to stubs mapping using standalone maven command:
|
||||
`mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:convert`
|
||||
|
||||
=== Limitations
|
||||
@@ -41,7 +44,7 @@ to turn it on, please set the value of the following system property to `true`:
|
||||
You can also provide the `assertJsonSize` property in the plugin configuration.
|
||||
|
||||
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.
|
||||
|
||||
=== Common Top-Level elements
|
||||
@@ -60,11 +63,18 @@ The following sections describe the most common top-level elements:
|
||||
You can add a `description` to your contract. The description is arbitrary text. The
|
||||
following code shows an example:
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{contract_spec_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=description,indent=0]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract_rest.yml[indent=0]
|
||||
----
|
||||
|
||||
[[contract-dsl-name]]
|
||||
==== Name
|
||||
|
||||
@@ -78,17 +88,36 @@ generated test not compile. Also, remember that, if you provide the same name fo
|
||||
multiple contracts, your autogenerated tests fail to compile and your generated stubs
|
||||
override each other.
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{contract_spec_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=name,indent=0]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=name,indent=0]
|
||||
----
|
||||
|
||||
[[contract-dsl-ignoring-contracts]]
|
||||
==== 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
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{contract_spec_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=ignored,indent=0]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=ignored,indent=0]
|
||||
----
|
||||
|
||||
[[contract-dsl-passing-values-from-files]]
|
||||
==== Passing Values from Files
|
||||
|
||||
@@ -108,11 +137,18 @@ following resources in our project.
|
||||
|
||||
Further assume that your contract is as follows:
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/classpath/readFromFile.groovy[indent=0]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract_from_file.yml[indent=0]
|
||||
----
|
||||
|
||||
Further assume that the JSON files is as follows:
|
||||
|
||||
*request.json*
|
||||
@@ -128,9 +164,8 @@ include::{verifier_core_path}/src/test/resources/classpath/response.json[indent=
|
||||
----
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
[[contract-dsl-http-top-level-elements]]
|
||||
==== HTTP Top-Level Elements
|
||||
@@ -138,62 +173,124 @@ lays.
|
||||
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
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=http_dsl,indent=0]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=priority,indent=0]
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
|
||||
...
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=response,indent=0]
|
||||
...
|
||||
----
|
||||
|
||||
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`.
|
||||
|
||||
=== Request
|
||||
|
||||
The HTTP protocol requires only **method and address** to be specified in a request. The
|
||||
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
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=request,indent=0]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request_obligatory,indent=0]
|
||||
----
|
||||
|
||||
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
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=url,indent=0]
|
||||
|
||||
----
|
||||
|
||||
`request` may contain **query parameters**, which are specified in a closure nested in a
|
||||
call to `urlPath` or `url`.
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract_rest_with_path.yml[tags=url_path,indent=0]
|
||||
----
|
||||
|
||||
`request` may contain **query parameters**.
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=urlpath,indent=0]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
|
||||
...
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=query_params,indent=0]
|
||||
----
|
||||
|
||||
`request` may contain additional **request headers**, as shown in the following example:
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=headers,indent=0]
|
||||
----
|
||||
|
||||
`request` may contain a **request body**, as shown in the following example:
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
|
||||
...
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=headers,indent=0]
|
||||
----
|
||||
|
||||
`request` may contain a **request body**:
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=body,indent=0]
|
||||
----
|
||||
|
||||
`request` may contain **multipart** elements. To include multipart elements, call the
|
||||
`multipart()` method, as shown in the following example
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
|
||||
...
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=body,indent=0]
|
||||
----
|
||||
|
||||
`request` may contain **multipart** elements. To include multipart elements, use the
|
||||
`multipart` method/section, as shown in the following examples
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy[tags=multipartdsl,indent=0]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract_multipart.yml[indent=0]
|
||||
----
|
||||
|
||||
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
|
||||
@@ -201,6 +298,20 @@ can set a `name` and `content`. You can call it either via a method with two ar
|
||||
such as `named("fileName", "fileContent")`, or via a map notation, such as
|
||||
`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:
|
||||
|
||||
[source,java,indent=0]
|
||||
@@ -227,17 +338,26 @@ The WireMock stub is as follows:
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/WireMockGroovyDslSpec.groovy[tags=multipartwiremock,indent=0]
|
||||
----
|
||||
|
||||
|
||||
=== Response
|
||||
|
||||
The response must contain an **HTTP status code** and may contain other information. The
|
||||
following code shows an example:
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=response,indent=0]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=response,indent=0]
|
||||
...
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=response_obligatory,indent=0]
|
||||
----
|
||||
|
||||
|
||||
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).
|
||||
|
||||
@@ -245,12 +365,19 @@ specified the same way as in the request (see the previous paragraph).
|
||||
|
||||
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`.
|
||||
|
||||
For YAML you can only use the `matchers` section.
|
||||
|
||||
==== Dynamic properties inside the body
|
||||
|
||||
IMPORTANT: This section is valid only for Groovy DSL. Check out the
|
||||
<<contract-matchers>> 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:
|
||||
@@ -278,6 +405,9 @@ method. Subsequent sections take a closer look at what you can do with those val
|
||||
|
||||
==== Regular expressions
|
||||
|
||||
IMPORTANT: This section is valid only for Groovy DSL. Check out the
|
||||
<<contract-matchers>> 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
|
||||
@@ -319,6 +449,9 @@ include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract
|
||||
|
||||
==== Passing Optional Parameters
|
||||
|
||||
IMPORTANT: This section is valid only for Groovy DSL. Check out the
|
||||
<<contract-matchers>> 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:
|
||||
|
||||
@@ -351,6 +484,9 @@ include::{plugins_path}/spring-cloud-contract-converters/src/test/groovy/org/spr
|
||||
|
||||
==== Executing Custom Methods on the Server Side
|
||||
|
||||
IMPORTANT: This section is valid only for Groovy DSL. Check out the
|
||||
<<contract-matchers>> 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:
|
||||
@@ -414,7 +550,9 @@ It should resemble the following code:
|
||||
==== 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:
|
||||
|
||||
@@ -430,13 +568,36 @@ given name.
|
||||
* `fromRequest().body(String jsonPath)`: Returns the element from the request that
|
||||
matches the JSON Path.
|
||||
|
||||
If you're using the YAML contract definition you have to use the
|
||||
http://handlebarsjs.com/[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
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy[tags=template_contract,indent=0]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract_reference_request.yml[indent=0]
|
||||
----
|
||||
|
||||
Running a JUnit test generation leads to a test that resembles the following example:
|
||||
|
||||
[source,java,indent=0]
|
||||
@@ -561,6 +722,7 @@ include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract
|
||||
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.
|
||||
|
||||
[[contract-matchers]]
|
||||
==== Dynamic Properties in the Matchers Sections
|
||||
|
||||
If you work with https://docs.pact.io/[Pact], the following discussion may seem familiar.
|
||||
@@ -577,6 +739,8 @@ contract.
|
||||
Currently, Spring Cloud Contract Verifier supports only JSON Path-based matchers with the
|
||||
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.
|
||||
@@ -615,13 +779,63 @@ following, depending on the JSON path:
|
||||
*** `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
|
||||
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
- 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]`:
|
||||
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
- 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
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderWithMatchersSpec.groovy[tags=matchers,indent=0]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract_matchers.yml[indent=0]
|
||||
----
|
||||
|
||||
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
|
||||
@@ -784,6 +998,7 @@ If you're using asynchronous communication on the server side (your controllers
|
||||
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:
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
org.springframework.cloud.contract.spec.Contract.make {
|
||||
@@ -799,6 +1014,13 @@ org.springframework.cloud.contract.spec.Contract.make {
|
||||
}
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
response:
|
||||
async: true
|
||||
----
|
||||
|
||||
=== Working with Context Paths
|
||||
|
||||
Spring Cloud Contract supports context paths.
|
||||
@@ -871,11 +1093,18 @@ following sections explain the differences:
|
||||
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:
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/samples-messaging-integration/src/test/groovy/com/example/IntegrationMessagingApplicationSpec.groovy[tags=method_trigger,indent=0]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract_message_method.yml[indent=0]
|
||||
----
|
||||
|
||||
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
|
||||
@@ -887,11 +1116,18 @@ the `some_label` to trigger the message.
|
||||
The output message can be triggered by receiving a message, as shown in the following
|
||||
example:
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy]
|
||||
----
|
||||
include::{tests_path}/samples-messaging-integration/src/test/groovy/com/example/IntegrationMessagingApplicationSpec.groovy[tags=message_trigger,indent=0]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract_message_input_message.yml[indent=0]
|
||||
----
|
||||
|
||||
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
|
||||
@@ -901,6 +1137,8 @@ generates a test that sends the input message to the defined destination. On the
|
||||
[[contract-dsl-consumer-producer]]
|
||||
==== Consumer/Producer
|
||||
|
||||
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
|
||||
@@ -915,21 +1153,28 @@ include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract
|
||||
[[contract-dsl-common]]
|
||||
==== Common
|
||||
|
||||
In the `input {}` or `outputMessage {}` section you can call `assertThat` with the name
|
||||
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.
|
||||
base class or in a static import. Spring Cloud Contract will execute that method
|
||||
in the generated test.
|
||||
|
||||
=== Multiple Contracts in One File
|
||||
|
||||
You can define multiple contracts in one file. Such a contract might resemble the
|
||||
following example:
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{plugins_path}/spring-cloud-contract-maven-plugin/src/test/projects/multiple-contracts/src/test/resources/contracts/com/hello/v1/WithList.groovy[lines=18..-1,indent=0]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/multiple_contracts.yml[indent=0]
|
||||
----
|
||||
|
||||
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:
|
||||
|
||||
@@ -1001,6 +1246,8 @@ your tests far more meaningful.
|
||||
|
||||
== Customization
|
||||
|
||||
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.
|
||||
|
||||
@@ -1102,13 +1349,6 @@ can generate stubs for other HTTP server implementations).
|
||||
|
||||
=== Custom Contract Converter
|
||||
|
||||
Assume that your contract is written in a YAML file as follows:
|
||||
|
||||
[source,yml]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/contract.yml[indent=0]
|
||||
----
|
||||
|
||||
The `ContractConverter` interface lets you register your own implementation of a contract
|
||||
structure converter. The following code listing shows the `ContractConverter` interface:
|
||||
|
||||
@@ -1128,15 +1368,8 @@ The following example shows a typical `spring.factories` file:
|
||||
|
||||
[source]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/META-INF/spring.factories[indent=0]
|
||||
----
|
||||
|
||||
The following example shows a typical YAML implementation that matches the preceding
|
||||
example:
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy[indent=0,lines=16..-1]
|
||||
org.springframework.cloud.contract.spec.ContractConverter=\
|
||||
org.springframework.cloud.contract.verifier.converter.YamlContractConverter
|
||||
----
|
||||
|
||||
==== Pact Converter
|
||||
|
||||
@@ -15,6 +15,10 @@ Spring Cloud Contract Verifier stand out on the "market" of Consumer Driven Cont
|
||||
- Stub Runner functionality - the stubs are automatically downloaded at runtime from Nexus / Artifactory
|
||||
- Spring Cloud integration - no discovery service is needed for integration tests
|
||||
|
||||
=== I don't want to write a contract in Groovy!
|
||||
|
||||
No problem. You can write a contract in YAML!
|
||||
|
||||
=== 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.
|
||||
@@ -370,4 +374,5 @@ for this for WireMock. In case of other HTTP server stubs you'll have to impleme
|
||||
==== 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.
|
||||
DSL and provide a path relative to where the contract lays.
|
||||
If you're using YAML just use the `bodyFromFile` property.
|
||||
@@ -106,11 +106,18 @@ Assume that you want to send a request containing the ID of a client company and
|
||||
amount it wants to borrow from us. You also want to send it to the /fraudcheck url via
|
||||
the PUT method.
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{introduction_url}/samples/standalone/dsl/http-server/src/test/resources/contracts/fraud/shouldMarkClientAsFraud.groovy[]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{introduction_url}/samples/standalone/yml/http-server/src/test/resources/contracts/fraud/shouldMarkClientAsFraud.yml[]
|
||||
----
|
||||
|
||||
==== Client Side
|
||||
|
||||
Spring Cloud Contract generates stubs, which you can use during client-side testing.
|
||||
@@ -144,7 +151,7 @@ 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:
|
||||
The autogenerated test looks, more or less, like this:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@@ -260,7 +267,7 @@ clone it.
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
git clone https://your-git-server.com/server-side.git local-http-server-repo
|
||||
$ 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.*
|
||||
@@ -271,13 +278,21 @@ your expectations. To do so, write the following contract:
|
||||
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.
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::{introduction_url}/samples/standalone/dsl/http-server/src/test/resources/contracts/fraud/shouldMarkClientAsFraud.groovy[]
|
||||
----
|
||||
|
||||
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
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{introduction_url}/samples/standalone/yml/http-server/src/test/resources/contracts/fraud/shouldMarkClientAsFraud.yml[]
|
||||
----
|
||||
|
||||
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
|
||||
@@ -333,8 +348,8 @@ stubs. You need to skip the test generation and execution. When you execute:
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
cd local-http-server-repo
|
||||
./mvnw clean install -DskipTests
|
||||
$ cd local-http-server-repo
|
||||
$ ./mvnw clean install -DskipTests
|
||||
----
|
||||
|
||||
In the logs, you see something like this:
|
||||
@@ -440,8 +455,8 @@ include::{introduction_url}/samples/standalone/dsl/http-server/src/main/java/com
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
git checkout -b contract-change-pr master
|
||||
git pull https://your-git-server.com/server-side-fork.git contract-change-pr
|
||||
$ 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:
|
||||
@@ -511,8 +526,9 @@ public void validate_shouldMarkClientAsFraud() throws Exception {
|
||||
}
|
||||
----
|
||||
|
||||
As you can see, all the `producer()` parts of the Contract that were present in the
|
||||
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,
|
||||
@@ -543,9 +559,9 @@ Once you finish your work, you can deploy your change. First, merge the branch:
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
git checkout master
|
||||
git merge --no-ff contract-change-pr
|
||||
git push origin master
|
||||
$ 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
|
||||
@@ -559,8 +575,8 @@ As a developer of the Loan Issuance service (a consumer of the Fraud Detection s
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
git checkout master
|
||||
git merge --no-ff contract-change-pr
|
||||
$ git checkout master
|
||||
$ git merge --no-ff contract-change-pr
|
||||
----
|
||||
|
||||
*Work online.*
|
||||
|
||||
@@ -89,11 +89,18 @@ it is resolved as a channel name. For *Camel*, that's a certain component (for e
|
||||
|
||||
Here is an example for Camel. For the given contract:
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=trigger_method_dsl]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract_message_scenario1.yml[indent=0]
|
||||
----
|
||||
|
||||
The following JUnit test is created:
|
||||
|
||||
[source,groovy]
|
||||
@@ -112,11 +119,18 @@ include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract
|
||||
|
||||
Here is an example for Camel. For the given contract:
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=trigger_message_dsl]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract_message_scenario2.yml[indent=0]
|
||||
----
|
||||
|
||||
The following JUnit test is created:
|
||||
|
||||
[source,groovy]
|
||||
@@ -135,11 +149,18 @@ include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract
|
||||
|
||||
Here is an example for Camel. For the given contract:
|
||||
|
||||
.Groovy DSL
|
||||
[source,groovy]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=trigger_no_output_dsl]
|
||||
----
|
||||
|
||||
.YAML
|
||||
[source,yml,indent=0]
|
||||
----
|
||||
include::{verifier_core_path}/src/test/resources/yml/contract_message_scenario3.yml[indent=0]
|
||||
----
|
||||
|
||||
The following JUnit test is created:
|
||||
|
||||
[source,groovy]
|
||||
|
||||
@@ -875,7 +875,8 @@ exclude the unwanted dependencies.
|
||||
|
||||
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:
|
||||
requires including an order number followed by an underscore. This will work regardles
|
||||
of whether you're working with YAML or Groovy. Example:
|
||||
|
||||
[source,indent=0]
|
||||
----
|
||||
|
||||
@@ -7,7 +7,7 @@ buildscript {
|
||||
maven { url "http://repo.spring.io/release" }
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.4.RELEASE"
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ buildscript {
|
||||
}
|
||||
// end::repos[]
|
||||
dependencies {
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.4.RELEASE"
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE"
|
||||
classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${findProperty('verifierVersion') ?: verifierVersion}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package contracts.fraudname
|
||||
|
||||
org.springframework.cloud.contract.spec.Contract.make {
|
||||
// highest priority
|
||||
priority(1)
|
||||
request {
|
||||
// highest priority
|
||||
priority(1)
|
||||
method PUT()
|
||||
url '/frauds/name'
|
||||
body([
|
||||
|
||||
@@ -7,7 +7,7 @@ buildscript {
|
||||
maven { url "http://repo.spring.io/release" }
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.4.RELEASE"
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ buildscript {
|
||||
maven { url "http://repo.spring.io/release" }
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.4.RELEASE"
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE"
|
||||
classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${findProperty('verifierVersion') ?: verifierVersion}"
|
||||
classpath "com.jayway.restassured:rest-assured:2.9.0"
|
||||
classpath "com.jayway.restassured:spring-mock-mvc:2.9.0"
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package contracts
|
||||
|
||||
org.springframework.cloud.contract.spec.Contract.make {
|
||||
request {
|
||||
method(GET())
|
||||
url("/foo")
|
||||
}
|
||||
response {
|
||||
status(200)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
description: Should return 200 for /foo
|
||||
request:
|
||||
url: /foo
|
||||
method: GET
|
||||
response:
|
||||
status: 200
|
||||
@@ -7,7 +7,7 @@ buildscript {
|
||||
maven { url "http://repo.spring.io/release" }
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.4.RELEASE"
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ buildscript {
|
||||
maven { url "http://repo.spring.io/release" }
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.4.RELEASE"
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE"
|
||||
classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${findProperty('verifierVersion') ?: verifierVersion}"
|
||||
//tag::pact_dependency[]
|
||||
classpath "org.springframework.cloud:spring-cloud-contract-spec-pact:${findProperty('verifierVersion') ?: verifierVersion}"
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
<module>dsl</module>
|
||||
<module>messaging</module>
|
||||
<module>pact</module>
|
||||
<module>yml</module>
|
||||
</modules>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -7,7 +7,7 @@ buildscript {
|
||||
maven { url "http://repo.spring.io/release" }
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.4.RELEASE"
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ buildscript {
|
||||
maven { url "http://repo.spring.io/plugins-staging-local/" }
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.4.RELEASE"
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
6
samples/standalone/yml/http-client/.gitignore
vendored
Normal file
6
samples/standalone/yml/http-client/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
target/
|
||||
|
||||
.gradle
|
||||
build/
|
||||
|
||||
1
samples/standalone/yml/http-client/.mvn/jvm.config
Normal file
1
samples/standalone/yml/http-client/.mvn/jvm.config
Normal file
@@ -0,0 +1 @@
|
||||
-Xmx1024m -XX:MaxPermSize=256m -Djava.awt.headless=true
|
||||
1
samples/standalone/yml/http-client/.mvn/maven.config
Normal file
1
samples/standalone/yml/http-client/.mvn/maven.config
Normal file
@@ -0,0 +1 @@
|
||||
-T2
|
||||
BIN
samples/standalone/yml/http-client/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
BIN
samples/standalone/yml/http-client/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
Binary file not shown.
1
samples/standalone/yml/http-client/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
1
samples/standalone/yml/http-client/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
@@ -0,0 +1 @@
|
||||
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip
|
||||
26
samples/standalone/yml/http-client/README.adoc
Normal file
26
samples/standalone/yml/http-client/README.adoc
Normal file
@@ -0,0 +1,26 @@
|
||||
= Http Client
|
||||
|
||||
== Prerequisites
|
||||
|
||||
First you have to publish to Maven Local the stubs of the *http-server* module
|
||||
|
||||
== How to run it?
|
||||
|
||||
Run
|
||||
|
||||
[source=groovy]
|
||||
--------
|
||||
./gradlew clean build
|
||||
--------
|
||||
|
||||
or
|
||||
|
||||
--------
|
||||
./mvnw clean package
|
||||
--------
|
||||
|
||||
To
|
||||
|
||||
- build the app
|
||||
- use spring-cloud-contract-stub-runner-spring[Stub Runner Spring] to download the stub of `Http Server`
|
||||
- run the tests against stubbed server
|
||||
64
samples/standalone/yml/http-client/build.gradle
Normal file
64
samples/standalone/yml/http-client/build.gradle
Normal file
@@ -0,0 +1,64 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
maven { url "http://repo.spring.io/snapshot" }
|
||||
maven { url "http://repo.spring.io/milestone" }
|
||||
maven { url "http://repo.spring.io/release" }
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE"
|
||||
}
|
||||
}
|
||||
|
||||
group = 'com.example'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
maven { url "http://repo.spring.io/snapshot" }
|
||||
maven { url "http://repo.spring.io/milestone" }
|
||||
maven { url "http://repo.spring.io/release" }
|
||||
}
|
||||
|
||||
apply plugin: 'groovy'
|
||||
apply plugin: 'org.springframework.boot'
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.cloud:spring-cloud-dependencies:$BOM_VERSION"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile("org.springframework.boot:spring-boot-starter-web")
|
||||
compile("org.springframework.boot:spring-boot-starter-actuator")
|
||||
|
||||
testCompile "org.springframework.cloud:spring-cloud-starter-contract-stub-runner"
|
||||
}
|
||||
|
||||
test {
|
||||
systemProperty 'spring.profiles.active', 'gradle'
|
||||
testLogging {
|
||||
exceptionFormat = 'full'
|
||||
}
|
||||
}
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
gradleVersion = '2.14'
|
||||
}
|
||||
|
||||
task resolveDependencies {
|
||||
doLast {
|
||||
project.rootProject.allprojects.each { subProject ->
|
||||
subProject.buildscript.configurations.each { configuration ->
|
||||
configuration.resolve()
|
||||
}
|
||||
subProject.configurations.each { configuration ->
|
||||
configuration.resolve()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
samples/standalone/yml/http-client/gradle.properties
Normal file
2
samples/standalone/yml/http-client/gradle.properties
Normal file
@@ -0,0 +1,2 @@
|
||||
org.gradle.daemon=false
|
||||
BOM_VERSION=Edgware.BUILD-SNAPSHOT
|
||||
BIN
samples/standalone/yml/http-client/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
samples/standalone/yml/http-client/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
samples/standalone/yml/http-client/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
samples/standalone/yml/http-client/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Fri Aug 19 15:39:05 CEST 2016
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.0-bin.zip
|
||||
164
samples/standalone/yml/http-client/gradlew
vendored
Executable file
164
samples/standalone/yml/http-client/gradlew
vendored
Executable file
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
90
samples/standalone/yml/http-client/gradlew.bat
vendored
Normal file
90
samples/standalone/yml/http-client/gradlew.bat
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
234
samples/standalone/yml/http-client/mvnw
vendored
Executable file
234
samples/standalone/yml/http-client/mvnw
vendored
Executable file
@@ -0,0 +1,234 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven2 Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# M2_HOME - location of maven2's installed home dir
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "`uname`" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
#
|
||||
# Look for the Apple JDKs first to preserve the existing behaviour, and then look
|
||||
# for the new JDKs provided by Oracle.
|
||||
#
|
||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then
|
||||
#
|
||||
# Oracle JDKs
|
||||
#
|
||||
export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=`/usr/libexec/java_home`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$M2_HOME" ] ; then
|
||||
## resolve links - $0 may be a link to maven's home
|
||||
PRG="$0"
|
||||
|
||||
# need this for relative symlinks
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG="`dirname "$PRG"`/$link"
|
||||
fi
|
||||
done
|
||||
|
||||
saveddir=`pwd`
|
||||
|
||||
M2_HOME=`dirname "$PRG"`/..
|
||||
|
||||
# make it fully qualified
|
||||
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||
|
||||
cd "$saveddir"
|
||||
# echo Using m2 at $M2_HOME
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Migwn, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
# TODO classpath?
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="`which javac`"
|
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=`which readlink`
|
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||
else
|
||||
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||
fi
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="`which java`"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
local basedir=$(pwd)
|
||||
local wdir=$(pwd)
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
wdir=$(cd "$wdir/.."; pwd)
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
fi
|
||||
}
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CMD_LINE_ARGS
|
||||
|
||||
145
samples/standalone/yml/http-client/mvnw.cmd
vendored
Normal file
145
samples/standalone/yml/http-client/mvnw.cmd
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven2 Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
set MAVEN_CMD_LINE_ARGS=%MAVEN_CONFIG% %*
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
|
||||
set WRAPPER_JAR=""%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar""
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||
|
||||
exit /B %ERROR_CODE%
|
||||
210
samples/standalone/yml/http-client/pom.xml
Normal file
210
samples/standalone/yml/http-client/pom.xml
Normal file
@@ -0,0 +1,210 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>http-client-yml</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
<name>Spring Cloud Contract Verifier Http Client Sample</name>
|
||||
<description>Spring Cloud Contract Verifier Http Client Sample</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.9.RELEASE</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<spring-cloud-dependencies.version>Edgware.BUILD-SNAPSHOT</spring-cloud-dependencies.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- tag::stub_runner[] -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- end::stub_runner[] -->
|
||||
|
||||
</dependencies>
|
||||
<!-- tag::contract_bom[] -->
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>${spring-cloud-dependencies.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<!-- end::contract_bom[] -->
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.8.2</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<configuration>
|
||||
<filesets>
|
||||
<fileset>
|
||||
<directory>build</directory>
|
||||
</fileset>
|
||||
<fileset>
|
||||
<directory>target</directory>
|
||||
</fileset>
|
||||
</filesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<url>https://repo.spring.io/release</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<url>https://repo.spring.io/release</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>integration</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>gradle</id>
|
||||
<phase>test</phase>
|
||||
<configuration>
|
||||
<executable>./gradlew</executable>
|
||||
<arguments>
|
||||
<argument>clean</argument>
|
||||
<argument>build</argument>
|
||||
<argument>publishToMavenLocal</argument>
|
||||
<argument>-PverifierVersion=${spring-cloud-contract.version}</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>windows</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>gradle</id>
|
||||
<phase>test</phase>
|
||||
<configuration>
|
||||
<executable>gradlew.bat</executable>
|
||||
<arguments>
|
||||
<argument>clean</argument>
|
||||
<argument>build</argument>
|
||||
<argument>publishToMavenLocal</argument>
|
||||
<argument>-PverifierVersion=${spring-cloud-contract.version}</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
||||
1
samples/standalone/yml/http-client/settings.gradle
Normal file
1
samples/standalone/yml/http-client/settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
rootProject.name = 'http-client-yml-gradle'
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.example.loan;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.example.loan;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.example.loan.model.FraudCheckStatus;
|
||||
import com.example.loan.model.FraudServiceRequest;
|
||||
import com.example.loan.model.FraudServiceResponse;
|
||||
import com.example.loan.model.LoanApplication;
|
||||
import com.example.loan.model.LoanApplicationResult;
|
||||
import com.example.loan.model.LoanApplicationStatus;
|
||||
import com.example.loan.model.Response;
|
||||
|
||||
@Service
|
||||
public class LoanApplicationService {
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
private int port = 6565;
|
||||
|
||||
@Autowired
|
||||
public LoanApplicationService(RestTemplateBuilder builder) {
|
||||
this.restTemplate = builder.build();
|
||||
}
|
||||
|
||||
public LoanApplicationResult loanApplication(LoanApplication loanApplication) {
|
||||
FraudServiceRequest request =
|
||||
new FraudServiceRequest(loanApplication);
|
||||
|
||||
FraudServiceResponse response =
|
||||
sendRequestToFraudDetectionService(request);
|
||||
|
||||
return buildResponseFromFraudResult(response);
|
||||
}
|
||||
|
||||
private FraudServiceResponse sendRequestToFraudDetectionService(
|
||||
FraudServiceRequest request) {
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||
|
||||
// tag::client_call_server[]
|
||||
ResponseEntity<FraudServiceResponse> response =
|
||||
restTemplate.exchange("http://localhost:" + port + "/fraudcheck", HttpMethod.PUT,
|
||||
new HttpEntity<>(request, httpHeaders),
|
||||
FraudServiceResponse.class);
|
||||
// end::client_call_server[]
|
||||
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
private LoanApplicationResult buildResponseFromFraudResult(FraudServiceResponse response) {
|
||||
LoanApplicationStatus applicationStatus = null;
|
||||
if (FraudCheckStatus.OK == response.getFraudCheckStatus()) {
|
||||
applicationStatus = LoanApplicationStatus.LOAN_APPLIED;
|
||||
} else if (FraudCheckStatus.FRAUD == response.getFraudCheckStatus()) {
|
||||
applicationStatus = LoanApplicationStatus.LOAN_APPLICATION_REJECTED;
|
||||
}
|
||||
|
||||
return new LoanApplicationResult(applicationStatus, response.getRejectionReason());
|
||||
}
|
||||
|
||||
public int countAllFrauds() {
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||
ResponseEntity<Response> response =
|
||||
restTemplate.exchange("http://localhost:" + port + "/frauds", HttpMethod.GET,
|
||||
new HttpEntity<>(httpHeaders),
|
||||
Response.class);
|
||||
return response.getBody().getCount();
|
||||
}
|
||||
|
||||
public int countDrunks() {
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||
ResponseEntity<Response> response =
|
||||
restTemplate.exchange("http://localhost:" + port + "/drunks", HttpMethod.GET,
|
||||
new HttpEntity<>(httpHeaders),
|
||||
Response.class);
|
||||
return response.getBody().getCount();
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.example.loan.model;
|
||||
|
||||
public class Client {
|
||||
|
||||
private String pesel;
|
||||
|
||||
public Client() {
|
||||
}
|
||||
|
||||
public Client(String pesel) {
|
||||
this.pesel = pesel;
|
||||
}
|
||||
|
||||
public String getPesel() {
|
||||
return pesel;
|
||||
}
|
||||
|
||||
public void setPesel(String pesel) {
|
||||
this.pesel = pesel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.example.loan.model;
|
||||
|
||||
public enum FraudCheckStatus {
|
||||
OK, FRAUD
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.example.loan.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class FraudServiceRequest {
|
||||
|
||||
@JsonProperty("client.id")
|
||||
private String clientId;
|
||||
|
||||
private BigDecimal loanAmount;
|
||||
|
||||
public FraudServiceRequest() {
|
||||
}
|
||||
|
||||
public FraudServiceRequest(LoanApplication loanApplication) {
|
||||
this.clientId = loanApplication.getClient().getPesel();
|
||||
this.loanAmount = loanApplication.getAmount();
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public BigDecimal getLoanAmount() {
|
||||
return loanAmount;
|
||||
}
|
||||
|
||||
public void setLoanAmount(BigDecimal loanAmount) {
|
||||
this.loanAmount = loanAmount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.example.loan.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class FraudServiceResponse {
|
||||
|
||||
private FraudCheckStatus fraudCheckStatus;
|
||||
|
||||
@JsonProperty("rejection.reason")
|
||||
private String rejectionReason;
|
||||
|
||||
public FraudServiceResponse() {
|
||||
}
|
||||
|
||||
public FraudCheckStatus getFraudCheckStatus() {
|
||||
return fraudCheckStatus;
|
||||
}
|
||||
|
||||
public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) {
|
||||
this.fraudCheckStatus = fraudCheckStatus;
|
||||
}
|
||||
|
||||
public String getRejectionReason() {
|
||||
return rejectionReason;
|
||||
}
|
||||
|
||||
public void setRejectionReason(String rejectionReason) {
|
||||
this.rejectionReason = rejectionReason;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.example.loan.model;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class LoanApplication {
|
||||
|
||||
private Client client;
|
||||
|
||||
private BigDecimal amount;
|
||||
|
||||
private String loanApplicationId;
|
||||
|
||||
public LoanApplication() {
|
||||
}
|
||||
|
||||
public LoanApplication(Client client, double amount) {
|
||||
this.client = client;
|
||||
this.amount = BigDecimal.valueOf(amount);
|
||||
}
|
||||
|
||||
public Client getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public void setClient(Client client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public String getLoanApplicationId() {
|
||||
return loanApplicationId;
|
||||
}
|
||||
|
||||
public void setLoanApplicationId(String loanApplicationId) {
|
||||
this.loanApplicationId = loanApplicationId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.example.loan.model;
|
||||
|
||||
public class LoanApplicationResult {
|
||||
|
||||
private LoanApplicationStatus loanApplicationStatus;
|
||||
|
||||
private String rejectionReason;
|
||||
|
||||
public LoanApplicationResult() {
|
||||
}
|
||||
|
||||
public LoanApplicationResult(LoanApplicationStatus loanApplicationStatus, String rejectionReason) {
|
||||
this.loanApplicationStatus = loanApplicationStatus;
|
||||
this.rejectionReason = rejectionReason;
|
||||
}
|
||||
|
||||
public LoanApplicationStatus getLoanApplicationStatus() {
|
||||
return loanApplicationStatus;
|
||||
}
|
||||
|
||||
public void setLoanApplicationStatus(LoanApplicationStatus loanApplicationStatus) {
|
||||
this.loanApplicationStatus = loanApplicationStatus;
|
||||
}
|
||||
|
||||
public String getRejectionReason() {
|
||||
return rejectionReason;
|
||||
}
|
||||
|
||||
public void setRejectionReason(String rejectionReason) {
|
||||
this.rejectionReason = rejectionReason;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.example.loan.model;
|
||||
|
||||
public enum LoanApplicationStatus {
|
||||
LOAN_APPLIED, LOAN_APPLICATION_REJECTED
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.example.loan.model;
|
||||
|
||||
public class Response {
|
||||
private int count;
|
||||
|
||||
public Response(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public Response() {
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return this.count;
|
||||
}
|
||||
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
server.port: 8090
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.example.loan;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.example.loan.model.Client;
|
||||
import com.example.loan.model.LoanApplication;
|
||||
import com.example.loan.model.LoanApplicationResult;
|
||||
import com.example.loan.model.LoanApplicationStatus;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment=WebEnvironment.NONE, properties="server.context-path=/app")
|
||||
@AutoConfigureStubRunner(ids = {"com.example:http-server-yml:+:stubs:6565"}, workOffline = true)
|
||||
@DirtiesContext
|
||||
public class LoanApplicationServiceContextPathTests {
|
||||
|
||||
@Autowired
|
||||
private LoanApplicationService service;
|
||||
|
||||
@Test
|
||||
public void shouldSuccessfullyApplyForLoan() {
|
||||
// given:
|
||||
LoanApplication application = new LoanApplication(new Client("1234567890"),
|
||||
123.123);
|
||||
// when:
|
||||
LoanApplicationResult loanApplication = service.loanApplication(application);
|
||||
// then:
|
||||
assertThat(loanApplication.getLoanApplicationStatus())
|
||||
.isEqualTo(LoanApplicationStatus.LOAN_APPLIED);
|
||||
assertThat(loanApplication.getRejectionReason()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeRejectedDueToAbnormalLoanAmount() {
|
||||
// given:
|
||||
LoanApplication application = new LoanApplication(new Client("1234567890"),
|
||||
99999);
|
||||
// when:
|
||||
LoanApplicationResult loanApplication = service.loanApplication(application);
|
||||
// then:
|
||||
assertThat(loanApplication.getLoanApplicationStatus())
|
||||
.isEqualTo(LoanApplicationStatus.LOAN_APPLICATION_REJECTED);
|
||||
assertThat(loanApplication.getRejectionReason()).isEqualTo("Amount too high");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.example.loan;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.example.loan.model.Client;
|
||||
import com.example.loan.model.LoanApplication;
|
||||
import com.example.loan.model.LoanApplicationResult;
|
||||
import com.example.loan.model.LoanApplicationStatus;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
// tag::autoconfigure_stubrunner[]
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
|
||||
@AutoConfigureStubRunner(ids = {"com.example:http-server-yml:+:stubs:6565"}, workOffline = true)
|
||||
@DirtiesContext
|
||||
public class LoanApplicationServiceTests {
|
||||
// end::autoconfigure_stubrunner[]
|
||||
|
||||
@Autowired
|
||||
private LoanApplicationService service;
|
||||
|
||||
@Test
|
||||
public void shouldSuccessfullyApplyForLoan() {
|
||||
// given:
|
||||
LoanApplication application = new LoanApplication(new Client("1234567890"),
|
||||
123.123);
|
||||
// when:
|
||||
LoanApplicationResult loanApplication = service.loanApplication(application);
|
||||
// then:
|
||||
assertThat(loanApplication.getLoanApplicationStatus())
|
||||
.isEqualTo(LoanApplicationStatus.LOAN_APPLIED);
|
||||
assertThat(loanApplication.getRejectionReason()).isNull();
|
||||
}
|
||||
|
||||
// tag::client_tdd[]
|
||||
@Test
|
||||
public void shouldBeRejectedDueToAbnormalLoanAmount() {
|
||||
// given:
|
||||
LoanApplication application = new LoanApplication(new Client("1234567890"),
|
||||
99999);
|
||||
// when:
|
||||
LoanApplicationResult loanApplication = service.loanApplication(application);
|
||||
// then:
|
||||
assertThat(loanApplication.getLoanApplicationStatus())
|
||||
.isEqualTo(LoanApplicationStatus.LOAN_APPLICATION_REJECTED);
|
||||
assertThat(loanApplication.getRejectionReason()).isEqualTo("Amount too high");
|
||||
}
|
||||
// end::client_tdd[]
|
||||
|
||||
@Test
|
||||
public void shouldSuccessfullyGetAllFrauds() {
|
||||
// when:
|
||||
int count = service.countAllFrauds();
|
||||
// then:
|
||||
assertThat(count).isEqualTo(200);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSuccessfullyGetAllDrunks() {
|
||||
// when:
|
||||
int count = service.countDrunks();
|
||||
// then:
|
||||
assertThat(count).isEqualTo(100);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
stubrunner:
|
||||
work-offline: true
|
||||
stubs.ids: 'com.example:http-server-dsl-gradle:+:stubs:6565'
|
||||
@@ -0,0 +1,3 @@
|
||||
stubrunner:
|
||||
ids: 'com.example:http-server-dsl:+:stubs:8080'
|
||||
repositoryRoot: http://repo.spring.io/libs-snapshot
|
||||
@@ -0,0 +1,2 @@
|
||||
server:
|
||||
port: 6565
|
||||
6
samples/standalone/yml/http-server/.gitignore
vendored
Normal file
6
samples/standalone/yml/http-server/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
target/
|
||||
|
||||
.gradle
|
||||
build/
|
||||
|
||||
1
samples/standalone/yml/http-server/.mvn/jvm.config
Normal file
1
samples/standalone/yml/http-server/.mvn/jvm.config
Normal file
@@ -0,0 +1 @@
|
||||
-Xmx1024m -XX:MaxPermSize=256m -Djava.awt.headless=true
|
||||
1
samples/standalone/yml/http-server/.mvn/maven.config
Normal file
1
samples/standalone/yml/http-server/.mvn/maven.config
Normal file
@@ -0,0 +1 @@
|
||||
-T2
|
||||
BIN
samples/standalone/yml/http-server/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
BIN
samples/standalone/yml/http-server/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
Binary file not shown.
1
samples/standalone/yml/http-server/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
1
samples/standalone/yml/http-server/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
@@ -0,0 +1 @@
|
||||
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip
|
||||
20
samples/standalone/yml/http-server/README.adoc
Normal file
20
samples/standalone/yml/http-server/README.adoc
Normal file
@@ -0,0 +1,20 @@
|
||||
= Http Server
|
||||
|
||||
Run
|
||||
|
||||
[source=groovy]
|
||||
--------
|
||||
./gradlew clean build publishToMavenLocal
|
||||
--------
|
||||
|
||||
or
|
||||
|
||||
--------
|
||||
./mvnw clean install
|
||||
--------
|
||||
|
||||
To
|
||||
|
||||
- build the app
|
||||
- generate and run Spring Cloud Contract Verifier tests
|
||||
- publish the fatJar and the stubs to Maven Local
|
||||
78
samples/standalone/yml/http-server/build.gradle
Normal file
78
samples/standalone/yml/http-server/build.gradle
Normal file
@@ -0,0 +1,78 @@
|
||||
// tag::repos[]
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
maven { url "http://repo.spring.io/snapshot" }
|
||||
maven { url "http://repo.spring.io/milestone" }
|
||||
maven { url "http://repo.spring.io/release" }
|
||||
}
|
||||
// end::repos[]
|
||||
dependencies {
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE"
|
||||
classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${findProperty('verifierVersion') ?: verifierVersion}"
|
||||
}
|
||||
}
|
||||
|
||||
group = 'com.example'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
|
||||
// tag::deps_repos[]
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
maven { url "http://repo.spring.io/snapshot" }
|
||||
maven { url "http://repo.spring.io/milestone" }
|
||||
maven { url "http://repo.spring.io/release" }
|
||||
}
|
||||
// end::deps_repos[]
|
||||
|
||||
apply plugin: 'groovy'
|
||||
apply plugin: 'org.springframework.boot'
|
||||
apply plugin: 'spring-cloud-contract'
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.cloud:spring-cloud-dependencies:$BOM_VERSION"
|
||||
}
|
||||
}
|
||||
|
||||
contracts {
|
||||
packageWithBaseClasses = 'com.example.fraud'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile("org.springframework.boot:spring-boot-starter-web")
|
||||
compile("org.springframework.boot:spring-boot-starter-actuator")
|
||||
|
||||
testCompile 'org.springframework.cloud:spring-cloud-starter-contract-verifier'
|
||||
}
|
||||
|
||||
test {
|
||||
systemProperty 'spring.profiles.active', 'gradle'
|
||||
testLogging {
|
||||
exceptionFormat = 'full'
|
||||
}
|
||||
}
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
gradleVersion = '2.14'
|
||||
}
|
||||
|
||||
clean.doFirst {
|
||||
delete "~/.m2/repository/com/example/http-server-dsl-gradle"
|
||||
}
|
||||
|
||||
task resolveDependencies {
|
||||
doLast {
|
||||
project.rootProject.allprojects.each { subProject ->
|
||||
subProject.buildscript.configurations.each { configuration ->
|
||||
configuration.resolve()
|
||||
}
|
||||
subProject.configurations.each { configuration ->
|
||||
configuration.resolve()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
samples/standalone/yml/http-server/gradle.properties
Normal file
3
samples/standalone/yml/http-server/gradle.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
org.gradle.daemon=false
|
||||
verifierVersion=1.2.2.BUILD-SNAPSHOT
|
||||
BOM_VERSION=Edgware.BUILD-SNAPSHOT
|
||||
BIN
samples/standalone/yml/http-server/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
samples/standalone/yml/http-server/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
samples/standalone/yml/http-server/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
samples/standalone/yml/http-server/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Fri Aug 19 15:38:58 CEST 2016
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.0-bin.zip
|
||||
164
samples/standalone/yml/http-server/gradlew
vendored
Executable file
164
samples/standalone/yml/http-server/gradlew
vendored
Executable file
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
90
samples/standalone/yml/http-server/gradlew.bat
vendored
Normal file
90
samples/standalone/yml/http-server/gradlew.bat
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
234
samples/standalone/yml/http-server/mvnw
vendored
Executable file
234
samples/standalone/yml/http-server/mvnw
vendored
Executable file
@@ -0,0 +1,234 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven2 Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# M2_HOME - location of maven2's installed home dir
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "`uname`" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
#
|
||||
# Look for the Apple JDKs first to preserve the existing behaviour, and then look
|
||||
# for the new JDKs provided by Oracle.
|
||||
#
|
||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then
|
||||
#
|
||||
# Oracle JDKs
|
||||
#
|
||||
export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=`/usr/libexec/java_home`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$M2_HOME" ] ; then
|
||||
## resolve links - $0 may be a link to maven's home
|
||||
PRG="$0"
|
||||
|
||||
# need this for relative symlinks
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG="`dirname "$PRG"`/$link"
|
||||
fi
|
||||
done
|
||||
|
||||
saveddir=`pwd`
|
||||
|
||||
M2_HOME=`dirname "$PRG"`/..
|
||||
|
||||
# make it fully qualified
|
||||
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||
|
||||
cd "$saveddir"
|
||||
# echo Using m2 at $M2_HOME
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Migwn, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
# TODO classpath?
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="`which javac`"
|
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=`which readlink`
|
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||
else
|
||||
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||
fi
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="`which java`"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
local basedir=$(pwd)
|
||||
local wdir=$(pwd)
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
wdir=$(cd "$wdir/.."; pwd)
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
fi
|
||||
}
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CMD_LINE_ARGS
|
||||
|
||||
145
samples/standalone/yml/http-server/mvnw.cmd
vendored
Normal file
145
samples/standalone/yml/http-server/mvnw.cmd
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven2 Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
set MAVEN_CMD_LINE_ARGS=%MAVEN_CONFIG% %*
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
|
||||
set WRAPPER_JAR=""%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar""
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||
|
||||
exit /B %ERROR_CODE%
|
||||
256
samples/standalone/yml/http-server/pom.xml
Normal file
256
samples/standalone/yml/http-server/pom.xml
Normal file
@@ -0,0 +1,256 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>http-server-yml</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
<name>Spring Cloud Contract Verifier Http Server Sample</name>
|
||||
<description>Spring Cloud Contract Verifier Http Server Sample</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.9.RELEASE</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<spring-cloud-contract.version>1.2.2.BUILD-SNAPSHOT</spring-cloud-contract.version>
|
||||
<spring-cloud-dependencies.version>Edgware.BUILD-SNAPSHOT</spring-cloud-dependencies.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- tag::verifier_test_dependencies[] -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-contract-verifier</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- end::verifier_test_dependencies[] -->
|
||||
</dependencies>
|
||||
|
||||
<!-- tag::contract_bom[] -->
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>${spring-cloud-dependencies.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<!-- end::contract_bom[] -->
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<!-- tag::contract_maven_plugin[] -->
|
||||
<plugin>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
|
||||
<version>${spring-cloud-contract.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<packageWithBaseClasses>com.example.fraud</packageWithBaseClasses>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- end::contract_maven_plugin[] -->
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.8.2</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<configuration>
|
||||
<filesets>
|
||||
<fileset>
|
||||
<directory>build</directory>
|
||||
</fileset>
|
||||
<fileset>
|
||||
<directory>target</directory>
|
||||
</fileset>
|
||||
</filesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings
|
||||
only. It has no influence on the Maven build itself. -->
|
||||
<plugin>
|
||||
<groupId>org.eclipse.m2e</groupId>
|
||||
<artifactId>lifecycle-mapping</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<configuration>
|
||||
<lifecycleMappingMetadata>
|
||||
<pluginExecutions>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
|
||||
<versionRange>[${spring-cloud-contract.version},)</versionRange>
|
||||
<goals>
|
||||
<goal>convert</goal>
|
||||
<goal>generateTests</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore></ignore>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
</pluginExecutions>
|
||||
</lifecycleMappingMetadata>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<!-- tag::repos[] -->
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<url>https://repo.spring.io/release</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<url>https://repo.spring.io/release</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
<!-- end::repos[] -->
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>integration</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>gradle</id>
|
||||
<phase>test</phase>
|
||||
<configuration>
|
||||
<executable>./gradlew</executable>
|
||||
<arguments>
|
||||
<argument>clean</argument>
|
||||
<argument>build</argument>
|
||||
<argument>publishToMavenLocal</argument>
|
||||
<argument>-PverifierVersion=${spring-cloud-contract.version}</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>windows</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>gradle</id>
|
||||
<phase>test</phase>
|
||||
<configuration>
|
||||
<executable>gradlew.bat</executable>
|
||||
<arguments>
|
||||
<argument>clean</argument>
|
||||
<argument>build</argument>
|
||||
<argument>publishToMavenLocal</argument>
|
||||
<argument>-PverifierVersion=${spring-cloud-contract.version}</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
1
samples/standalone/yml/http-server/settings.gradle
Normal file
1
samples/standalone/yml/http-server/settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
rootProject.name = 'http-server-yml-gradle'
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.example.fraud;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.example.fraud;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.example.fraud.model.FraudCheck;
|
||||
import com.example.fraud.model.FraudCheckResult;
|
||||
import com.example.fraud.model.FraudCheckStatus;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
|
||||
|
||||
@RestController
|
||||
public class FraudDetectionController {
|
||||
|
||||
private static final String NO_REASON = null;
|
||||
private static final String AMOUNT_TOO_HIGH = "Amount too high";
|
||||
private static final BigDecimal MAX_AMOUNT = new BigDecimal("5000");
|
||||
|
||||
// tag::server_api[]
|
||||
@RequestMapping(value = "/fraudcheck", method = PUT)
|
||||
public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) {
|
||||
// end::server_api[]
|
||||
// tag::new_impl[]
|
||||
if (amountGreaterThanThreshold(fraudCheck)) {
|
||||
return new FraudCheckResult(FraudCheckStatus.FRAUD, AMOUNT_TOO_HIGH);
|
||||
}
|
||||
// end::new_impl[]
|
||||
// tag::initial_impl[]
|
||||
return new FraudCheckResult(FraudCheckStatus.OK, NO_REASON);
|
||||
// end::initial_impl[]
|
||||
}
|
||||
|
||||
private boolean amountGreaterThanThreshold(FraudCheck fraudCheck) {
|
||||
return MAX_AMOUNT.compareTo(fraudCheck.getLoanAmount()) < 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.example.fraud;
|
||||
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@RestController
|
||||
class FraudNameController {
|
||||
|
||||
private final FraudVerifier fraudVerifier;
|
||||
|
||||
FraudNameController(FraudVerifier fraudVerifier) {
|
||||
this.fraudVerifier = fraudVerifier;
|
||||
}
|
||||
|
||||
@PutMapping(value = "/frauds/name")
|
||||
public NameResponse checkByName(@RequestBody NameRequest request) {
|
||||
boolean fraud = this.fraudVerifier.isFraudByName(request.getName());
|
||||
if (fraud) {
|
||||
return new NameResponse("Sorry " + request.getName() + " but you're a fraud");
|
||||
}
|
||||
return new NameResponse("Don't worry " + request.getName() + " you're not a fraud");
|
||||
}
|
||||
}
|
||||
|
||||
interface FraudVerifier {
|
||||
boolean isFraudByName(String name);
|
||||
}
|
||||
|
||||
class NameRequest {
|
||||
private String name;
|
||||
|
||||
public NameRequest(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public NameRequest() {
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
class NameResponse {
|
||||
private String result;
|
||||
|
||||
public NameResponse(String result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public NameResponse() {
|
||||
}
|
||||
|
||||
public String getResult() {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
public void setResult(String result) {
|
||||
this.result = result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.example.fraud;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class FraudStatsController {
|
||||
|
||||
private final StatsProvider statsProvider;
|
||||
|
||||
public FraudStatsController(StatsProvider statsProvider) {
|
||||
this.statsProvider = statsProvider;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/frauds")
|
||||
public Response countAllFrauds() {
|
||||
return new Response(this.statsProvider.count(FraudType.ALL));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/drunks")
|
||||
public Response countAllDrunks() {
|
||||
return new Response(this.statsProvider.count(FraudType.DRUNKS));
|
||||
}
|
||||
}
|
||||
|
||||
enum FraudType {
|
||||
DRUNKS, ALL
|
||||
}
|
||||
|
||||
interface StatsProvider {
|
||||
int count(FraudType fraudType);
|
||||
}
|
||||
|
||||
class Response {
|
||||
private int count;
|
||||
|
||||
public Response(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public Response() {
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return this.count;
|
||||
}
|
||||
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.example.fraud.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class FraudCheck {
|
||||
|
||||
@JsonProperty("client.id")
|
||||
private String clientId;
|
||||
|
||||
private BigDecimal loanAmount;
|
||||
|
||||
public FraudCheck() {
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public BigDecimal getLoanAmount() {
|
||||
return loanAmount;
|
||||
}
|
||||
|
||||
public void setLoanAmount(BigDecimal loanAmount) {
|
||||
this.loanAmount = loanAmount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.example.fraud.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class FraudCheckResult {
|
||||
|
||||
private FraudCheckStatus fraudCheckStatus;
|
||||
|
||||
@JsonProperty("rejection.reason")
|
||||
private String rejectionReason;
|
||||
|
||||
public FraudCheckResult() {
|
||||
}
|
||||
|
||||
public FraudCheckResult(FraudCheckStatus fraudCheckStatus, String rejectionReason) {
|
||||
this.fraudCheckStatus = fraudCheckStatus;
|
||||
this.rejectionReason = rejectionReason;
|
||||
}
|
||||
|
||||
public FraudCheckStatus getFraudCheckStatus() {
|
||||
return fraudCheckStatus;
|
||||
}
|
||||
|
||||
public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) {
|
||||
this.fraudCheckStatus = fraudCheckStatus;
|
||||
}
|
||||
|
||||
public String getRejectionReason() {
|
||||
return rejectionReason;
|
||||
}
|
||||
|
||||
public void setRejectionReason(String rejectionReason) {
|
||||
this.rejectionReason = rejectionReason;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.example.fraud.model;
|
||||
|
||||
public enum FraudCheckStatus {
|
||||
OK, FRAUD
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
server.port=0
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.example.fraud;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
||||
|
||||
public class FraudBase {
|
||||
@Before
|
||||
public void setup() {
|
||||
RestAssuredMockMvc.standaloneSetup(new FraudDetectionController(),
|
||||
new FraudStatsController(stubbedStatsProvider()));
|
||||
}
|
||||
|
||||
private StatsProvider stubbedStatsProvider() {
|
||||
return fraudType -> {
|
||||
switch (fraudType) {
|
||||
case DRUNKS:
|
||||
return 100;
|
||||
case ALL:
|
||||
return 200;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
public void assertThatRejectionReasonIsNull(Object rejectionReason) {
|
||||
assert rejectionReason == null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.example.fraud;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
||||
|
||||
public class FraudnameBase {
|
||||
|
||||
private static final String FRAUD_NAME = "fraud";
|
||||
|
||||
FraudVerifier fraudVerifier = FRAUD_NAME::equals;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
RestAssuredMockMvc.standaloneSetup(new FraudNameController(this.fraudVerifier));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
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`
|
||||
@@ -0,0 +1,25 @@
|
||||
request:
|
||||
method: PUT
|
||||
url: /fraudcheck
|
||||
body:
|
||||
"client.id": 1234567890
|
||||
loanAmount: 123.123
|
||||
headers:
|
||||
Content-Type: application/json
|
||||
matchers:
|
||||
body:
|
||||
- path: $.['client.id']
|
||||
type: by_regex
|
||||
value: "[0-9]{10}"
|
||||
response:
|
||||
status: 200
|
||||
body:
|
||||
fraudCheckStatus: "OK"
|
||||
"rejection.reason": null
|
||||
headers:
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
matchers:
|
||||
body:
|
||||
- path: $.['rejection.reason']
|
||||
type: by_command
|
||||
value: assertThatRejectionReasonIsNull($it)
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
name: "should count all frauds"
|
||||
request:
|
||||
method: GET
|
||||
url: /frauds
|
||||
response:
|
||||
status: 200
|
||||
body:
|
||||
count: 200
|
||||
headers:
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
---
|
||||
request:
|
||||
method: GET
|
||||
url: /drunks
|
||||
response:
|
||||
status: 200
|
||||
body:
|
||||
count: 100
|
||||
headers:
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
@@ -0,0 +1,15 @@
|
||||
# highest priority
|
||||
priority: 1
|
||||
request:
|
||||
method: PUT
|
||||
url: /frauds/name
|
||||
body:
|
||||
name: "fraud"
|
||||
headers:
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
response:
|
||||
status: 200
|
||||
body:
|
||||
result: "Sorry {{{ jsonpath this '$.name' }}} but you're a fraud"
|
||||
headers:
|
||||
Content-Type: "{{{ request.headers.Content-Type.0 }}}"
|
||||
@@ -0,0 +1,18 @@
|
||||
request:
|
||||
method: PUT
|
||||
url: /frauds/name
|
||||
body:
|
||||
name: "non fraud"
|
||||
headers:
|
||||
Content-Type: application/json
|
||||
matchers:
|
||||
body:
|
||||
- path: $.name
|
||||
type: by_regex
|
||||
predefined: only_alpha_unicode
|
||||
response:
|
||||
status: 200
|
||||
body:
|
||||
result: "Don't worry {{{ jsonpath this '$.name' }}} you're not a fraud"
|
||||
headers:
|
||||
Content-Type: "{{{ request.headers.Content-Type.0 }}};charset=UTF-8"
|
||||
40
samples/standalone/yml/pom.xml
Normal file
40
samples/standalone/yml/pom.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-samples-standalone</artifactId>
|
||||
<version>1.2.2.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>spring-cloud-contract-samples-yml</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Spring Cloud Contract Standalone Dsl Test Samples</name>
|
||||
<description>Spring Cloud Contract Standalone Test Samples used for end to end tests</description>
|
||||
|
||||
<properties>
|
||||
<spring-cloud-contract.version>1.2.2.BUILD-SNAPSHOT</spring-cloud-contract.version>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>http-server</module>
|
||||
<module>http-client</module>
|
||||
</modules>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.8.2</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -31,7 +31,8 @@ import groovy.transform.ToString
|
||||
class Body extends DslProperty {
|
||||
|
||||
Body(Map<String, DslProperty> body) {
|
||||
super(extractValue(body, { DslProperty p -> p.clientValue}), extractValue(body, {DslProperty p -> p.serverValue}))
|
||||
super(extractValue(body, { p -> p instanceof DslProperty ? ((DslProperty) p).clientValue : p }),
|
||||
extractValue(body, { p -> p instanceof DslProperty ? ((DslProperty) p).serverValue : p }))
|
||||
}
|
||||
|
||||
private static Map<String, Object> extractValue(Map<String, DslProperty> body, Closure valueProvider) {
|
||||
|
||||
@@ -15,7 +15,7 @@ import groovy.transform.ToString
|
||||
@ToString(includeFields = true, includePackage = false)
|
||||
class BodyMatchers {
|
||||
private final RegexPatterns regexPatterns = new RegexPatterns()
|
||||
private final List<BodyMatcher> jsonPathRegexMatchers = []
|
||||
protected final List<BodyMatcher> jsonPathRegexMatchers = []
|
||||
|
||||
void jsonPath(String path, MatchingTypeValue matchingType) {
|
||||
this.jsonPathRegexMatchers << new JsonPathBodyMatcher(path, matchingType)
|
||||
|
||||
@@ -91,6 +91,18 @@ class Headers {
|
||||
} as Map<String , Object>
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the headers into their stub side representations and returns as
|
||||
* a map of String key => Object value.
|
||||
*/
|
||||
Map<String , Object> asTestSideMap() {
|
||||
def acc = [:].withDefault { [] as Collection<Object> }
|
||||
return entries.inject(acc as Map<String, Object>) { Map<String, Object> map, Header header ->
|
||||
map[header.name] = header.serverValue
|
||||
return map
|
||||
} as Map<String , Object>
|
||||
}
|
||||
|
||||
boolean equals(o) {
|
||||
if (this.is(o)) return true
|
||||
if (getClass() != o.class) return false
|
||||
|
||||
@@ -94,6 +94,15 @@ then:
|
||||
// end::description[]
|
||||
}
|
||||
|
||||
def 'should set a name'() {
|
||||
given:
|
||||
// tag::name[]
|
||||
org.springframework.cloud.contract.spec.Contract.make {
|
||||
name("some_special_name")
|
||||
}
|
||||
// end::name[]
|
||||
}
|
||||
|
||||
def 'should mark a contract ignored'() {
|
||||
given:
|
||||
// tag::ignored[]
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.cloud.contract.spec.Contract;
|
||||
import org.springframework.cloud.contract.spec.ContractConverter;
|
||||
import org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockHttpServerStub;
|
||||
import org.springframework.cloud.contract.verifier.converter.YamlContractConverter;
|
||||
import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
|
||||
@@ -165,11 +166,15 @@ class StubRepository {
|
||||
BasicFileAttributes attrs) throws IOException {
|
||||
File file = path.toFile();
|
||||
ContractConverter converter = contractConverter(file);
|
||||
if (isContractDescriptor(file) && isStubPerConsumerPathMatching(file)) {
|
||||
contractDescriptors
|
||||
.addAll(ContractVerifierDslConverter.convertAsCollection(file.getParentFile(), file));
|
||||
} else if (converter != null && isStubPerConsumerPathMatching(file)) {
|
||||
contractDescriptors.addAll(converter.convertFrom(file));
|
||||
if (isStubPerConsumerPathMatching(file)) {
|
||||
if (isContractDescriptor(file)) {
|
||||
contractDescriptors
|
||||
.addAll(ContractVerifierDslConverter.convertAsCollection(file.getParentFile(), file));
|
||||
} else if (YamlContractConverter.INSTANCE.isAccepted(file)) {
|
||||
contractDescriptors.addAll(YamlContractConverter.INSTANCE.convertFrom(file));
|
||||
} else if (converter != null) {
|
||||
contractDescriptors.addAll(converter.convertFrom(file));
|
||||
}
|
||||
}
|
||||
return super.visitFile(path, attrs);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ ext {
|
||||
]
|
||||
}
|
||||
|
||||
project.version = findProperty('verifierVersion') ?: '1.5.4.RELEASE'
|
||||
project.version = findProperty('verifierVersion') ?: '1.5.9.RELEASE'
|
||||
apply plugin: 'groovy'
|
||||
apply from: "$rootDir/gradle/release.gradle"
|
||||
apply plugin: 'eclipse'
|
||||
|
||||
@@ -20,7 +20,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.4.RELEASE")
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ buildscript {
|
||||
mavenLocal()
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.4.RELEASE")
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ buildscript {
|
||||
mavenLocal()
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.4.RELEASE")
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,9 @@ import org.codehaus.plexus.archiver.jar.JarArchiver;
|
||||
public class GenerateStubsMojo extends AbstractMojo {
|
||||
|
||||
private static final String STUB_MAPPING_FILE_PATTERN = "**/*.json";
|
||||
private static final String CONTRACT_FILE_PATTERN = "**/*.groovy";
|
||||
private static final String GROOVY_CONTRACT_FILE_PATTERN = "**/*.groovy";
|
||||
private static final String YAML_CONTRACT_FILE_PATTERN = "**/*.yaml";
|
||||
private static final String YML_CONTRACT_FILE_PATTERN = "**/*.yml";
|
||||
|
||||
@Parameter(defaultValue = "${project.build.directory}", readonly = true,
|
||||
required = true)
|
||||
@@ -110,7 +112,10 @@ public class GenerateStubsMojo extends AbstractMojo {
|
||||
try {
|
||||
if (this.attachContracts) {
|
||||
this.archiver.addDirectory(stubsOutputDir,
|
||||
new String[] { STUB_MAPPING_FILE_PATTERN, CONTRACT_FILE_PATTERN },
|
||||
new String[] { STUB_MAPPING_FILE_PATTERN,
|
||||
GROOVY_CONTRACT_FILE_PATTERN,
|
||||
YAML_CONTRACT_FILE_PATTERN,
|
||||
YML_CONTRACT_FILE_PATTERN },
|
||||
excludedFilesEmpty() ? new String[0] : this.excludedFiles);
|
||||
}
|
||||
else {
|
||||
@@ -134,7 +139,9 @@ public class GenerateStubsMojo extends AbstractMojo {
|
||||
|
||||
private String[] excludes() {
|
||||
List<String> excludes = new ArrayList<>();
|
||||
excludes.add(CONTRACT_FILE_PATTERN);
|
||||
excludes.add(GROOVY_CONTRACT_FILE_PATTERN);
|
||||
excludes.add(YAML_CONTRACT_FILE_PATTERN);
|
||||
excludes.add(YML_CONTRACT_FILE_PATTERN);
|
||||
if (!excludedFilesEmpty()) {
|
||||
excludes.addAll(Arrays.asList(this.excludedFiles));
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.4.RELEASE</version>
|
||||
<version>1.5.9.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.4.RELEASE</version>
|
||||
<version>1.5.9.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.4.RELEASE</version>
|
||||
<version>1.5.9.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-test-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-messaging</artifactId>
|
||||
@@ -81,6 +85,10 @@
|
||||
<groupId>com.github.jknack</groupId>
|
||||
<artifactId>handlebars</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib</artifactId>
|
||||
@@ -105,11 +113,6 @@
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.rest-assured</groupId>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
|
||||
@@ -187,7 +187,6 @@ class ClassPresenceChecker {
|
||||
|
||||
boolean isClassPresent(String className) {
|
||||
try {
|
||||
|
||||
Class.forName(className)
|
||||
return true
|
||||
} catch (ClassNotFoundException e) {
|
||||
|
||||
@@ -63,12 +63,24 @@ class MethodBuilder {
|
||||
|
||||
static String methodName(ContractMetadata contract, File stubsFile, Contract stubContent) {
|
||||
if (stubContent.name) {
|
||||
return NamesUtil.camelCase(NamesUtil.convertIllegalPackageChars(stubContent.name))
|
||||
String name = NamesUtil.camelCase(NamesUtil.convertIllegalPackageChars(stubContent.name))
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Overriding the default test name with [" + name + "]")
|
||||
}
|
||||
return name
|
||||
} else if (contract.convertedContract.size() > 1) {
|
||||
int index = contract.convertedContract.findIndexOf { it == stubContent}
|
||||
return "${camelCasedMethodFromFileName(stubsFile)}_${index}"
|
||||
String name = "${camelCasedMethodFromFileName(stubsFile)}_${index}"
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Scenario found. The method name will be [" + name + "]")
|
||||
}
|
||||
return name
|
||||
}
|
||||
return camelCasedMethodFromFileName(stubsFile)
|
||||
String name = camelCasedMethodFromFileName(stubsFile)
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("The method name will be [" + name + "]")
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
private static String camelCasedMethodFromFileName(File stubsFile) {
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.converter
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
|
||||
/**
|
||||
* YAML representation of a {@link org.springframework.cloud.contract.spec.Contract}
|
||||
*
|
||||
* @since 1.2.1
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@CompileStatic
|
||||
class YamlContract {
|
||||
public Request request
|
||||
public Response response
|
||||
public Input input
|
||||
public OutputMessage outputMessage
|
||||
public String description
|
||||
public String label
|
||||
public String name
|
||||
public Integer priority
|
||||
public boolean ignored
|
||||
|
||||
@CompileStatic
|
||||
static class Request {
|
||||
public String method
|
||||
public String url
|
||||
public String urlPath
|
||||
public Map<String, Object> queryParameters = [:]
|
||||
public Map<String, Object> headers = [:]
|
||||
public Object body
|
||||
public String bodyFromFile
|
||||
public StubMatchers matchers = new StubMatchers()
|
||||
public Multipart multipart
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static class Multipart {
|
||||
public Map<String, String> params = [:]
|
||||
public List<Named> named = []
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static class Named {
|
||||
public String paramName
|
||||
public String fileName
|
||||
public String fileContent
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static class StubMatchers {
|
||||
public List<BodyStubMatcher> body = []
|
||||
public List<KeyValueMatcher> headers = []
|
||||
public MultipartStubMatcher multipart
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static class BodyStubMatcher {
|
||||
public String path
|
||||
public StubMatcherType type
|
||||
public String value
|
||||
public PredefinedRegex predefined
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static class MultipartStubMatcher {
|
||||
public List<KeyValueMatcher> params = []
|
||||
public List<MultipartNamedStubMatcher> named = []
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static class MultipartNamedStubMatcher {
|
||||
public String paramName
|
||||
public ValueMatcher fileName
|
||||
public ValueMatcher fileContent
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static class ValueMatcher {
|
||||
public String regex
|
||||
public PredefinedRegex predefined
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static class BodyTestMatcher {
|
||||
public String path
|
||||
public TestMatcherType type
|
||||
public String value
|
||||
public Integer minOccurrence
|
||||
public Integer maxOccurrence
|
||||
public PredefinedRegex predefined
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static class KeyValueMatcher {
|
||||
public String key
|
||||
public String regex
|
||||
public PredefinedRegex predefined
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static class TestHeaderMatcher {
|
||||
public String key
|
||||
public String regex
|
||||
public String command
|
||||
public PredefinedRegex predefined
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static enum PredefinedRegex {
|
||||
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
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static enum StubMatcherType {
|
||||
by_date, by_time, by_timestamp, by_regex, by_equality
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static enum TestMatcherType {
|
||||
by_date, by_time, by_timestamp, by_regex, by_equality, by_type, by_command
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static class Response {
|
||||
public int status
|
||||
public Map<String, Object> headers = [:]
|
||||
public Object body
|
||||
public String bodyFromFile
|
||||
public TestMatchers matchers = new TestMatchers()
|
||||
public Boolean async
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static class TestMatchers {
|
||||
public List<BodyTestMatcher> body = []
|
||||
public List<TestHeaderMatcher> headers = []
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static class Input {
|
||||
public String messageFrom
|
||||
public String triggeredBy
|
||||
public Map<String, Object> messageHeaders = [:]
|
||||
public Object messageBody
|
||||
public String messageBodyFromFile
|
||||
public String assertThat
|
||||
public StubMatchers matchers = new StubMatchers()
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static class OutputMessage {
|
||||
public String sentTo
|
||||
public Map<String, Object> headers = [:]
|
||||
public Object body
|
||||
public String bodyFromFile
|
||||
public String assertThat
|
||||
public TestMatchers matchers = new TestMatchers()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,556 @@
|
||||
/*
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.converter
|
||||
|
||||
import java.nio.file.Files
|
||||
import java.util.regex.Pattern
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import groovy.transform.CompileStatic
|
||||
import org.yaml.snakeyaml.Yaml
|
||||
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
import org.springframework.cloud.contract.spec.ContractConverter
|
||||
import org.springframework.cloud.contract.spec.internal.BodyMatcher
|
||||
import org.springframework.cloud.contract.spec.internal.DslProperty
|
||||
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
|
||||
import org.springframework.cloud.contract.spec.internal.Headers
|
||||
import org.springframework.cloud.contract.spec.internal.MatchingType
|
||||
import org.springframework.cloud.contract.spec.internal.MatchingTypeValue
|
||||
import org.springframework.cloud.contract.spec.internal.NamedProperty
|
||||
import org.springframework.cloud.contract.spec.internal.RegexPatterns
|
||||
import org.springframework.cloud.contract.verifier.converter.YamlContract.BodyStubMatcher
|
||||
import org.springframework.cloud.contract.verifier.converter.YamlContract.BodyTestMatcher
|
||||
import org.springframework.cloud.contract.verifier.converter.YamlContract.Input
|
||||
import org.springframework.cloud.contract.verifier.converter.YamlContract.Named
|
||||
import org.springframework.cloud.contract.verifier.converter.YamlContract.OutputMessage
|
||||
import org.springframework.cloud.contract.verifier.converter.YamlContract.PredefinedRegex
|
||||
import org.springframework.cloud.contract.verifier.converter.YamlContract.Request
|
||||
import org.springframework.cloud.contract.verifier.converter.YamlContract.Response
|
||||
import org.springframework.cloud.contract.verifier.converter.YamlContract.KeyValueMatcher
|
||||
import org.springframework.cloud.contract.verifier.converter.YamlContract.StubMatcherType
|
||||
import org.springframework.cloud.contract.verifier.converter.YamlContract.StubMatchers
|
||||
import org.springframework.cloud.contract.verifier.converter.YamlContract.TestHeaderMatcher
|
||||
import org.springframework.cloud.contract.verifier.converter.YamlContract.TestMatcherType
|
||||
import org.springframework.cloud.contract.verifier.util.MapConverter
|
||||
|
||||
/**
|
||||
* Simple converter from and to a {@link YamlContract} to a collection of {@link Contract}
|
||||
*
|
||||
* @since 1.2.1
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@CompileStatic
|
||||
class YamlContractConverter implements ContractConverter<List<YamlContract>> {
|
||||
|
||||
public static final YamlContractConverter INSTANCE = new YamlContractConverter()
|
||||
|
||||
@Override
|
||||
boolean isAccepted(File file) {
|
||||
String name = file.getName()
|
||||
return name.endsWith(".yml") || name.endsWith(".yaml")
|
||||
}
|
||||
|
||||
@Override
|
||||
Collection<Contract> convertFrom(File contractFile) {
|
||||
ClassLoader classLoader = YamlContractConverter.getClassLoader()
|
||||
ObjectMapper mapper = new ObjectMapper()
|
||||
try {
|
||||
return new Yaml().loadAll(Files.newInputStream(contractFile.toPath())).collect {
|
||||
YamlContract yamlContract = mapper.convertValue(it, YamlContract.class);
|
||||
Thread.currentThread().setContextClassLoader(updatedClassLoader(contractFile.getParentFile(), classLoader))
|
||||
return Contract.make {
|
||||
if (yamlContract.description) description(yamlContract.description)
|
||||
if (yamlContract.label) label(yamlContract.label)
|
||||
if (yamlContract.name) name(yamlContract.name)
|
||||
if (yamlContract.priority) priority(yamlContract.priority)
|
||||
if (yamlContract.ignored) ignored()
|
||||
if (yamlContract.request?.method) {
|
||||
request {
|
||||
method(yamlContract.request?.method)
|
||||
if (yamlContract.request?.url) {
|
||||
url(yamlContract.request?.url) {
|
||||
if (yamlContract.request.queryParameters) {
|
||||
queryParameters {
|
||||
yamlContract.request.queryParameters.each { String key, Object value ->
|
||||
if (value instanceof List) {
|
||||
((List) value).each {
|
||||
parameter(key, it)
|
||||
}
|
||||
} else {
|
||||
parameter(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (yamlContract.request?.urlPath) {
|
||||
urlPath(yamlContract.request?.urlPath) {
|
||||
if (yamlContract.request.queryParameters) {
|
||||
queryParameters {
|
||||
yamlContract.request.queryParameters.each { String key, Object value ->
|
||||
if (value instanceof List) {
|
||||
((List) value).each {
|
||||
parameter(key, it)
|
||||
}
|
||||
} else {
|
||||
parameter(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (yamlContract.request?.headers) {
|
||||
headers {
|
||||
yamlContract.request?.headers?.each { String key, Object value ->
|
||||
KeyValueMatcher matcher = yamlContract.request.matchers.headers.find { it.key == key }
|
||||
if (value instanceof List) {
|
||||
((List) value).each {
|
||||
Object clientValue = clientValue(it, matcher, key)
|
||||
header(key, new DslProperty(clientValue, it))
|
||||
}
|
||||
} else {
|
||||
Object clientValue = clientValue(value, matcher, key)
|
||||
header(key, new DslProperty(clientValue, value))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (yamlContract.request.body) body(yamlContract.request.body)
|
||||
if (yamlContract.request.bodyFromFile) body(file(yamlContract.request.bodyFromFile))
|
||||
if (yamlContract.request.multipart) {
|
||||
Map multipartMap = [:]
|
||||
Map<String, DslProperty> multiPartParams = yamlContract.request.multipart.params.collectEntries { String paramKey, String paramValue ->
|
||||
KeyValueMatcher matcher = yamlContract.request.matchers.multipart.params.find {
|
||||
it.key == paramKey
|
||||
}
|
||||
Object value = paramValue
|
||||
if (matcher) {
|
||||
value = matcher.regex ? Pattern.compile(matcher.regex) :
|
||||
predefinedToPattern(matcher.predefined)
|
||||
}
|
||||
return [(paramKey), new DslProperty<>(value, paramValue)]
|
||||
} as Map<String, DslProperty>
|
||||
multipartMap.putAll(multiPartParams)
|
||||
yamlContract.request.multipart.named.each { Named namedParam ->
|
||||
YamlContract.MultipartNamedStubMatcher matcher = yamlContract.request.matchers.multipart.named.find {
|
||||
it.paramName == namedParam.paramName
|
||||
}
|
||||
Object fileNameValue = namedParam.fileName
|
||||
Object fileContentValue = namedParam.fileContent
|
||||
if (matcher && matcher.fileName) {
|
||||
fileNameValue = matcher.fileName.regex ? Pattern.compile(matcher.fileName.regex) :
|
||||
predefinedToPattern(matcher.fileName.predefined)
|
||||
}
|
||||
if (matcher && matcher.fileContent) {
|
||||
fileContentValue = matcher.fileContent.regex ? Pattern.compile(matcher.fileContent.regex) :
|
||||
predefinedToPattern(matcher.fileContent.predefined)
|
||||
}
|
||||
multipartMap.put(namedParam.paramName, new NamedProperty(new DslProperty<>(fileNameValue, namedParam.fileName),
|
||||
new DslProperty<>(fileContentValue, namedParam.fileContent)))
|
||||
}
|
||||
multipart(multipartMap)
|
||||
}
|
||||
stubMatchers {
|
||||
yamlContract.request.matchers?.body?.each { BodyStubMatcher matcher ->
|
||||
MatchingTypeValue value = null
|
||||
switch (matcher.type) {
|
||||
case StubMatcherType.by_date:
|
||||
value = byDate()
|
||||
break
|
||||
case StubMatcherType.by_time:
|
||||
value = byTime()
|
||||
break
|
||||
case StubMatcherType.by_timestamp:
|
||||
value = byTimestamp()
|
||||
break
|
||||
case StubMatcherType.by_regex:
|
||||
String regex = matcher.value
|
||||
if (matcher.predefined) {
|
||||
regex = predefinedToPattern(matcher.predefined).pattern()
|
||||
}
|
||||
value = byRegex(regex)
|
||||
break
|
||||
case StubMatcherType.by_equality:
|
||||
value = byEquality()
|
||||
break
|
||||
}
|
||||
jsonPath(matcher.path, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
response {
|
||||
status(yamlContract.response.status)
|
||||
headers {
|
||||
yamlContract.response?.headers?.each { String key, Object value ->
|
||||
TestHeaderMatcher matcher = yamlContract.response.matchers.headers.find { it.key == key }
|
||||
if (value instanceof List) {
|
||||
((List) value).each {
|
||||
Object serverValue = serverValue(it, matcher, key)
|
||||
header(key, new DslProperty(it, serverValue))
|
||||
}
|
||||
} else {
|
||||
Object serverValue = serverValue(value, matcher, key)
|
||||
header(key, new DslProperty(value, serverValue))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (yamlContract.response.body) body(yamlContract.response.body)
|
||||
if (yamlContract.response.bodyFromFile) body(file(yamlContract.response.bodyFromFile))
|
||||
if (yamlContract.response.async) async()
|
||||
testMatchers {
|
||||
yamlContract.response?.matchers?.body?.each { BodyTestMatcher testMatcher ->
|
||||
MatchingTypeValue value = null
|
||||
switch (testMatcher.type) {
|
||||
case TestMatcherType.by_date:
|
||||
value = byDate()
|
||||
break
|
||||
case TestMatcherType.by_time:
|
||||
value = byTime()
|
||||
break
|
||||
case TestMatcherType.by_timestamp:
|
||||
value = byTimestamp()
|
||||
break
|
||||
case TestMatcherType.by_regex:
|
||||
String regex = testMatcher.value
|
||||
if (testMatcher.predefined) {
|
||||
regex = predefinedToPattern(testMatcher.predefined).pattern()
|
||||
}
|
||||
value = byRegex(regex)
|
||||
break
|
||||
case TestMatcherType.by_equality:
|
||||
value = byEquality()
|
||||
break
|
||||
case TestMatcherType.by_type:
|
||||
value = byType() {
|
||||
if (testMatcher.minOccurrence != null) minOccurrence(testMatcher.minOccurrence)
|
||||
if (testMatcher.maxOccurrence != null) maxOccurrence(testMatcher.maxOccurrence)
|
||||
}
|
||||
break
|
||||
case TestMatcherType.by_command:
|
||||
value = byCommand(testMatcher.value)
|
||||
break
|
||||
}
|
||||
jsonPath(testMatcher.path, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (yamlContract.input) {
|
||||
input {
|
||||
if (yamlContract.input.messageFrom) messageFrom(yamlContract.input.messageFrom)
|
||||
if (yamlContract.input.assertThat) assertThat(yamlContract.input.assertThat)
|
||||
if (yamlContract.input.triggeredBy) triggeredBy(yamlContract.input.triggeredBy)
|
||||
messageHeaders {
|
||||
yamlContract.input?.messageHeaders?.each { String key, Object value ->
|
||||
KeyValueMatcher matcher = yamlContract.input.matchers?.headers?.find { it.key == key }
|
||||
Object clientValue = clientValue(value, matcher, key)
|
||||
header(key, new DslProperty(clientValue, value))
|
||||
}
|
||||
}
|
||||
if (yamlContract.input.messageBody) messageBody(yamlContract.input.messageBody)
|
||||
if (yamlContract.input.messageBodyFromFile) messageBody(file(yamlContract.input.messageBodyFromFile))
|
||||
stubMatchers {
|
||||
yamlContract.input.matchers.body?.each { BodyStubMatcher matcher ->
|
||||
MatchingTypeValue value = null
|
||||
switch (matcher.type) {
|
||||
case StubMatcherType.by_date:
|
||||
value = byDate()
|
||||
break
|
||||
case StubMatcherType.by_time:
|
||||
value = byTime()
|
||||
break
|
||||
case StubMatcherType.by_timestamp:
|
||||
value = byTimestamp()
|
||||
break
|
||||
case StubMatcherType.by_regex:
|
||||
value = byRegex(matcher.value)
|
||||
break
|
||||
case StubMatcherType.by_equality:
|
||||
value = byEquality()
|
||||
break
|
||||
}
|
||||
jsonPath(matcher.path, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
OutputMessage outputMsg = yamlContract.outputMessage
|
||||
if (outputMsg) {
|
||||
outputMessage {
|
||||
if (outputMsg.assertThat) assertThat(outputMsg.assertThat)
|
||||
if (outputMsg.sentTo) sentTo(outputMsg.sentTo)
|
||||
headers {
|
||||
outputMsg.headers?.each { String key, Object value ->
|
||||
TestHeaderMatcher matcher = outputMsg.matchers?.headers?.find { it.key == key }
|
||||
Object serverValue = serverValue(value, matcher, key)
|
||||
header(key, new DslProperty(value, serverValue))
|
||||
}
|
||||
}
|
||||
if (outputMsg.body) body(outputMsg.body)
|
||||
if (outputMsg.bodyFromFile) body(file(outputMsg.bodyFromFile))
|
||||
if (outputMsg.matchers) {
|
||||
testMatchers {
|
||||
yamlContract.outputMessage?.matchers?.body?.each { BodyTestMatcher testMatcher ->
|
||||
MatchingTypeValue value = null
|
||||
switch (testMatcher.type) {
|
||||
case TestMatcherType.by_date:
|
||||
value = byDate()
|
||||
break
|
||||
case TestMatcherType.by_time:
|
||||
value = byTime()
|
||||
break
|
||||
case TestMatcherType.by_timestamp:
|
||||
value = byTimestamp()
|
||||
break
|
||||
case TestMatcherType.by_regex:
|
||||
value = byRegex(testMatcher.value)
|
||||
break
|
||||
case TestMatcherType.by_equality:
|
||||
value = byEquality()
|
||||
break
|
||||
case TestMatcherType.by_type:
|
||||
value = byType() {
|
||||
if (testMatcher.minOccurrence != null) minOccurrence(testMatcher.minOccurrence)
|
||||
if (testMatcher.maxOccurrence != null) maxOccurrence(testMatcher.maxOccurrence)
|
||||
}
|
||||
break
|
||||
case TestMatcherType.by_command:
|
||||
value = byCommand(testMatcher.value)
|
||||
break
|
||||
}
|
||||
jsonPath(testMatcher.path, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
throw new IllegalStateException(e)
|
||||
}
|
||||
catch (IllegalStateException ise) {
|
||||
throw ise
|
||||
}
|
||||
catch (Exception e1) {
|
||||
throw new IllegalStateException("Exception occurred while processing the file [" + contractFile + "]", e1)
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(classLoader)
|
||||
}
|
||||
}
|
||||
|
||||
protected Object serverValue(Object value, TestHeaderMatcher matcher, String key) {
|
||||
Object serverValue = value
|
||||
if (matcher?.regex) {
|
||||
serverValue = Pattern.compile(matcher.regex)
|
||||
Pattern pattern = (Pattern) serverValue
|
||||
assertPatternMatched(pattern, value, key)
|
||||
} else if (matcher?.predefined) {
|
||||
Pattern pattern = predefinedToPattern(matcher.predefined)
|
||||
serverValue = pattern
|
||||
assertPatternMatched(pattern, value, key)
|
||||
} else if (matcher?.command) {
|
||||
serverValue = new ExecutionProperty(matcher.command)
|
||||
}
|
||||
return serverValue
|
||||
}
|
||||
|
||||
protected Object clientValue(Object value, KeyValueMatcher matcher, String key) {
|
||||
Object clientValue = value
|
||||
if (matcher?.regex) {
|
||||
clientValue = Pattern.compile(matcher.regex)
|
||||
Pattern pattern = (Pattern) clientValue
|
||||
assertPatternMatched(pattern, value, key)
|
||||
} else if (matcher?.predefined) {
|
||||
Pattern pattern = predefinedToPattern(matcher.predefined)
|
||||
clientValue = pattern
|
||||
assertPatternMatched(pattern, value, key)
|
||||
}
|
||||
return clientValue
|
||||
}
|
||||
|
||||
private void assertPatternMatched(Pattern pattern, value, String key) {
|
||||
boolean matches = pattern.matcher(value.toString()).matches()
|
||||
if (!matches) throw new IllegalStateException("Broken headers! A header with " +
|
||||
"key [${key}] with value [${value}] is not matched by regex [${pattern.pattern()}]")
|
||||
}
|
||||
|
||||
protected Pattern predefinedToPattern(PredefinedRegex predefinedRegex) {
|
||||
RegexPatterns patterns = new RegexPatterns()
|
||||
switch (predefinedRegex) {
|
||||
case PredefinedRegex.only_alpha_unicode:
|
||||
return Pattern.compile(patterns.onlyAlphaUnicode())
|
||||
case PredefinedRegex.number:
|
||||
return Pattern.compile(patterns.number())
|
||||
case PredefinedRegex.any_boolean:
|
||||
return Pattern.compile(patterns.anyBoolean())
|
||||
case PredefinedRegex.ip_address:
|
||||
return Pattern.compile(patterns.ipAddress())
|
||||
case PredefinedRegex.hostname:
|
||||
return Pattern.compile(patterns.hostname())
|
||||
case PredefinedRegex.email:
|
||||
return Pattern.compile(patterns.email())
|
||||
case PredefinedRegex.url:
|
||||
return Pattern.compile(patterns.url())
|
||||
case PredefinedRegex.uuid:
|
||||
return Pattern.compile(patterns.uuid())
|
||||
case PredefinedRegex.iso_date:
|
||||
return Pattern.compile(patterns.isoDate())
|
||||
case PredefinedRegex.iso_date_time:
|
||||
return Pattern.compile(patterns.isoDateTime())
|
||||
case PredefinedRegex.iso_time:
|
||||
return Pattern.compile(patterns.isoTime())
|
||||
case PredefinedRegex.iso_8601_with_offset:
|
||||
return Pattern.compile(patterns.iso8601WithOffset())
|
||||
case PredefinedRegex.non_empty:
|
||||
return Pattern.compile(patterns.nonEmpty())
|
||||
case PredefinedRegex.non_blank:
|
||||
return Pattern.compile(patterns.nonBlank())
|
||||
}
|
||||
}
|
||||
|
||||
protected String file(String relativePath) {
|
||||
URL resource = Thread.currentThread().getContextClassLoader().getResource(relativePath)
|
||||
if (resource == null) {
|
||||
throw new IllegalStateException("File [${relativePath}] is not present")
|
||||
}
|
||||
return new File(resource.toURI()).text
|
||||
}
|
||||
|
||||
protected static ClassLoader updatedClassLoader(File rootFolder, ClassLoader classLoader) {
|
||||
ClassLoader urlCl = URLClassLoader
|
||||
.newInstance([rootFolder.toURI().toURL()] as URL[], classLoader)
|
||||
Thread.currentThread().setContextClassLoader(urlCl)
|
||||
return urlCl
|
||||
}
|
||||
|
||||
@Override
|
||||
List<YamlContract> convertTo(Collection<Contract> contracts) {
|
||||
return contracts.collect { Contract contract ->
|
||||
YamlContract yamlContract = new YamlContract()
|
||||
if (contract?.request?.method) {
|
||||
yamlContract.request = new Request()
|
||||
yamlContract.request.with {
|
||||
method = contract?.request?.method?.clientValue
|
||||
url = contract?.request?.url?.clientValue
|
||||
headers = (contract?.request?.headers as Headers)?.asTestSideMap()
|
||||
body = MapConverter.getTestSideValues(contract?.request?.body)
|
||||
matchers = new StubMatchers()
|
||||
contract?.request?.matchers?.jsonPathMatchers()?.each { BodyMatcher matcher ->
|
||||
matchers.body << new BodyStubMatcher(
|
||||
path: matcher.path(),
|
||||
type: stubMatcherType(matcher.matchingType()),
|
||||
value: matcher.value()?.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
yamlContract.response = new Response()
|
||||
yamlContract.response.with {
|
||||
status = contract?.response?.status?.clientValue as Integer
|
||||
headers = (contract?.response?.headers as Headers)?.asStubSideMap()
|
||||
body = MapConverter.getStubSideValues(contract?.response?.body)
|
||||
contract?.response?.matchers?.jsonPathMatchers()?.each { BodyMatcher matcher ->
|
||||
matchers.body << new BodyTestMatcher(
|
||||
path: matcher.path(),
|
||||
type: testMatcherType(matcher.matchingType()),
|
||||
value: matcher.value()?.toString(),
|
||||
minOccurrence: matcher.minTypeOccurrence(),
|
||||
maxOccurrence: matcher.maxTypeOccurrence()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (contract.input) {
|
||||
yamlContract.input = new Input()
|
||||
yamlContract.input.assertThat = contract?.input?.assertThat?.toString()
|
||||
yamlContract.input.triggeredBy = contract?.input?.triggeredBy?.toString()
|
||||
yamlContract.input.messageHeaders = (contract?.input?.messageHeaders as Headers)?.asTestSideMap()
|
||||
yamlContract.input.messageBody = MapConverter.getTestSideValues(contract?.input?.messageBody)
|
||||
yamlContract.input.messageFrom = contract?.input?.messageFrom?.serverValue
|
||||
yamlContract.input.matchers.body.each {
|
||||
contract?.input?.matchers?.jsonPathMatchers()?.each { BodyMatcher matcher ->
|
||||
yamlContract.input.matchers.body << new BodyStubMatcher(
|
||||
path: matcher.path(),
|
||||
type: stubMatcherType(matcher.matchingType()),
|
||||
value: matcher.value()?.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (contract.outputMessage) {
|
||||
yamlContract.outputMessage = new OutputMessage()
|
||||
yamlContract.outputMessage.headers = (contract?.outputMessage?.headers as Headers)?.asStubSideMap()
|
||||
yamlContract.outputMessage.body = MapConverter.getStubSideValues(contract?.outputMessage?.body)
|
||||
yamlContract.outputMessage.matchers.body.each {
|
||||
contract?.input?.matchers?.jsonPathMatchers()?.each { BodyMatcher matcher ->
|
||||
yamlContract.outputMessage.matchers.body << new BodyTestMatcher(
|
||||
path: matcher.path(),
|
||||
type: testMatcherType(matcher.matchingType()),
|
||||
value: matcher.value()?.toString(),
|
||||
minOccurrence: matcher.minTypeOccurrence(),
|
||||
maxOccurrence: matcher.maxTypeOccurrence()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return yamlContract
|
||||
}
|
||||
}
|
||||
|
||||
protected TestMatcherType testMatcherType(MatchingType matchingType) {
|
||||
switch (matchingType) {
|
||||
case MatchingType.EQUALITY:
|
||||
return TestMatcherType.by_equality
|
||||
case MatchingType.TYPE:
|
||||
return TestMatcherType.by_type
|
||||
case MatchingType.COMMAND:
|
||||
return TestMatcherType.by_command
|
||||
case MatchingType.DATE:
|
||||
return TestMatcherType.by_date
|
||||
case MatchingType.TIME:
|
||||
return TestMatcherType.by_time
|
||||
case MatchingType.TIMESTAMP:
|
||||
return TestMatcherType.by_timestamp
|
||||
case MatchingType.REGEX:
|
||||
return TestMatcherType.by_regex
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
protected StubMatcherType stubMatcherType(MatchingType matchingType) {
|
||||
switch (matchingType) {
|
||||
case MatchingType.EQUALITY:
|
||||
return StubMatcherType.by_equality
|
||||
case MatchingType.TYPE:
|
||||
case MatchingType.COMMAND:
|
||||
throw new UnsupportedOperationException("No type for client side")
|
||||
case MatchingType.DATE:
|
||||
return StubMatcherType.by_date
|
||||
case MatchingType.TIME:
|
||||
return StubMatcherType.by_time
|
||||
case MatchingType.TIMESTAMP:
|
||||
return StubMatcherType.by_timestamp
|
||||
case MatchingType.REGEX:
|
||||
return StubMatcherType.by_regex
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user