diff --git a/docs/src/main/asciidoc/_additional-stubrunner-configprops.adoc b/docs/src/main/asciidoc/_additional-stubrunner-configprops.adoc index 6fed50c24b..cf35b933e8 100644 --- a/docs/src/main/asciidoc/_additional-stubrunner-configprops.adoc +++ b/docs/src/main/asciidoc/_additional-stubrunner-configprops.adoc @@ -4,8 +4,6 @@ IMPORTANT: The following properties can be passed as a system property (for exam |=== |Name | Default | Description -|`stubrunner.properties.pactbroker.provider-name-with-group-id` | `false` | When using the Pact Broker-based approach, you can automatically group ID to the provider name. - |`stubrunner.properties.git.branch` | | When using the SCM-based approach, you can customize the branch name to check out. |`stubrunner.properties.git.commit-message` | Updating project [$project] with stubs | When using the SCM based approach, you can customize the commit message for created stubs. The `$project` text is replaced with the project name. |`stubrunner.properties.git.no-of-attempts` | `10` | When using the-SCM based approach, you can customize the number of retries to push the stubs to Git. diff --git a/docs/src/main/asciidoc/_attributes.adoc b/docs/src/main/asciidoc/_attributes.adoc index a112c97bca..8b47f24221 100644 --- a/docs/src/main/asciidoc/_attributes.adoc +++ b/docs/src/main/asciidoc/_attributes.adoc @@ -36,4 +36,3 @@ :doc_samples_url: {samples_url}/wiremock-for-contract-docs :wiremock_tests: {core_path}/spring-cloud-contract-wiremock :introduction_url: {core_path} -:standalone_pact_path: {samples_url}/ diff --git a/docs/src/main/asciidoc/_index.adoc b/docs/src/main/asciidoc/_index.adoc index 7203e7798b..a73417931f 100644 --- a/docs/src/main/asciidoc/_index.adoc +++ b/docs/src/main/asciidoc/_index.adoc @@ -14,5 +14,5 @@ The reference documentation consists of the following sections: <> :: {project-full-name} usage examples and workflows. <> :: Contract DSL, Messaging, Spring Cloud Contract Stub Runner, and Spring Cloud Contract WireMock. <> :: Maven Plugin, Gradle Plugin, and Docker. -<> :: Stubs versioning, Pact integration, Debugging, and more. +<> :: Stubs versioning, Debugging, and more. <> :: Properties, Metadata, Configuration, Dependencies, and more. diff --git a/docs/src/main/asciidoc/documentation-overview.adoc b/docs/src/main/asciidoc/documentation-overview.adoc index cb2633b7e7..3c2b5b0f75 100644 --- a/docs/src/main/asciidoc/documentation-overview.adoc +++ b/docs/src/main/asciidoc/documentation-overview.adoc @@ -96,7 +96,6 @@ Need more details about {project-full-name}'s core features? <> | <> | <> -<> * *Modules:* <> | <> diff --git a/docs/src/main/asciidoc/gradle-project.adoc b/docs/src/main/asciidoc/gradle-project.adoc index 57d7866c9d..6af996c9cd 100644 --- a/docs/src/main/asciidoc/gradle-project.adoc +++ b/docs/src/main/asciidoc/gradle-project.adoc @@ -112,7 +112,7 @@ buildscript { dependencies { classpath "org.springframework.boot:spring-boot-gradle-plugin:${springboot_version}" classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifier_version}" - // here you can also pass additional dependencies such as Pact or Kotlin spec e.g.: + // here you can also pass additional dependencies such as Kotlin spec e.g.: // classpath "org.springframework.cloud:spring-cloud-contract-spec-kotlin:${verifier_version}" } } diff --git a/docs/src/main/asciidoc/howto.adoc b/docs/src/main/asciidoc/howto.adoc index 4a94772f27..76c30db2e7 100644 --- a/docs/src/main/asciidoc/howto.adoc +++ b/docs/src/main/asciidoc/howto.adoc @@ -28,7 +28,6 @@ Spring Cloud Contract Verifier stand out on the market of Consumer Driven Contra - Automatic generation of tests from the defined contract. - Stub Runner functionality: The stubs are automatically downloaded at runtime from Nexus or Artifactory. - Spring Cloud integration: No discovery service is needed for integration tests. -- Spring Cloud Contract integrates with Pact and provides easy hooks to extend its functionality. - Ability to add support for any language & framework through Docker. [[how-to-not-write-contracts-in-groovy]] @@ -831,427 +830,6 @@ to find stub definitions and contracts. For example, for `com.example:foo:1.0.0` * Stub servers are started and fed with mappings. * Messaging definitions are read and used in the messaging tests. -[[how-to-use-pact-broker]] -== How Can I Use the Pact Broker? - -When using https://pact.io/[Pact], you can use the https://github.com/pact-foundation/pact_broker[Pact Broker] -to store and share Pact definitions. Starting from Spring Cloud Contract -2.0.0, you can fetch Pact files from the Pact Broker to generate -tests and stubs. - -IMPORTANT: Pact follows the consumer contract convention. That means -that the consumer creates the Pact definitions first and then -shares the files with the Producer. Those expectations are generated -from the Consumer's code and can break the Producer if the expectations -are not met. - -[[how-to-use-pact-broker-pact]] -=== How to Work with Pact - -Spring Cloud Contract includes support for the https://docs.pact.io/[Pact] representation of -contracts up until version 4. Instead of using the DSL, you can use Pact files. In this section, we -show how to add Pact support for your project. Note, however, that not all functionality is supported. -Starting with version 3, you can combine multiple matchers for the same element: -You can use matchers for the body, headers, request and path, and you can use value generators. -Spring Cloud Contract currently only supports multiple matchers that are combined by using the `AND` rule logic. -Next to that, the request and path matchers are skipped during the conversion. -When using a date, time, or datetime value generator with a given format, -the given format is skipped and the ISO format is used. - -[[how-to-use-pact-broker-pact-converter]] -=== Pact Converter - -In order to properly support the Spring Cloud Contract way of doing messaging -with Pact, you have to provide some additional metadata entries. - -To define the destination to which a message gets sent, you have to -set a `metaData` entry in the Pact file with the `sentTo` key equal to the destination to - which a message is to be sent (for example, `"metaData": { "sentTo": "activemq:output" }`). - -[[how-to-use-pact-broker-pact-contract]] -=== Pact Contract - -Spring Cloud Contract can read the Pact JSON definition. You can place the file in the -`src/test/resources/contracts` folder. Remember to put the `spring-cloud-contract-pact` dependency to your classpath. - -[[how-to-use-pact-broker-pact-for-producers]] -=== Pact for Producers - -On the producer side, you must add two additional dependencies to your plugin -configuration. One is the Spring Cloud Contract Pact support, and the other represents -the current Pact version that you use. The following listing shows how to do so for both -Maven and Gradle: - -==== -[source,xml,indent=0,subs="verbatim,attributes",role="primary"] -.Maven ----- -include::{standalone_pact_path}/producer_pact/pom.xml[tags=pact_dependency,indent=0] ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Gradle ----- -include::{standalone_pact_path}/producer_pact/build.gradle[tags=pact_dependency,indent=0] ----- -==== - -When you build your application, a test and stub is generated. The following -example shows a test and stub that came from this process: - -==== -[source,java,indent=0,subs="verbatim,attributes",role="primary"] -.test ----- -@Test - public void validate_shouldMarkClientAsFraud() throws Exception { - // given: - MockMvcRequestSpecification request = given() - .header("Content-Type", "application/vnd.fraud.v1+json") - .body("{\"clientId\":\"1234567890\",\"loanAmount\":99999}"); - - // when: - ResponseOptions response = given().spec(request) - .put("/fraudcheck"); - - // then: - assertThat(response.statusCode()).isEqualTo(200); - assertThat(response.header("Content-Type")).matches("application/vnd\\.fraud\\.v1\\+json.*"); - // and: - DocumentContext parsedJson = JsonPath.parse(response.getBody().asString()); - assertThatJson(parsedJson).field("['rejectionReason']").isEqualTo("Amount too high"); - // and: - assertThat(parsedJson.read("$.fraudCheckStatus", String.class)).matches("FRAUD"); - } ----- - -[source,json,indent=0,subs="verbatim,attributes",role="secondary"] -.stub ----- -{ - "id" : "996ae5ae-6834-4db6-8fac-358ca187ab62", - "uuid" : "996ae5ae-6834-4db6-8fac-358ca187ab62", - "request" : { - "url" : "/fraudcheck", - "method" : "PUT", - "headers" : { - "Content-Type" : { - "matches" : "application/vnd\\.fraud\\.v1\\+json.*" - } - }, - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['loanAmount'] = 99999)]" - }, { - "matchesJsonPath" : "$[?(@.clientId =~ /([0-9]{10})/)]" - } ] - }, - "response" : { - "status" : 200, - "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}", - "headers" : { - "Content-Type" : "application/vnd.fraud.v1+json;charset=UTF-8" - }, - "transformers" : [ "response-template" ] - }, -} ----- -==== - -[[how-to-use-pact-broker-pact-consumers]] -=== Pact for Consumers - -On the consumer side, you must add two additional dependencies to your project -dependencies. One is the Spring Cloud Contract Pact support, and the other represents the -current Pact version that you use. The following listing shows how to do so for both -Maven and Gradle: - -==== -[source,xml,indent=0,subs="verbatim,attributes",role="primary"] -.Maven ----- -include::{standalone_pact_path}/consumer_pact_stubrunner/pom.xml[tags=pact_dependency,indent=0] ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Gradle ----- -include::{standalone_pact_path}/consumer_pact_stubrunner/build.gradle[tags=pact_dependency,indent=0] ----- -==== - -[[pact-stub-downloader]] -=== Communicating with the Pact Broker - -Whenever the `repositoryRoot` property starts with a Pact protocol -(that is, starts with `pact://`), the stub downloader tries -to fetch the Pact contract definitions from the Pact Broker. -Whatever is set after `pact://` is parsed as the Pact Broker URL. - -By setting environment variables, system properties, or properties set -inside the plugin or contracts repository configuration, you can -tweak the downloader's behavior. The following table describes the -properties: - -.Pact Stub Downloader properties -|==== -|Name of a property |Default | Description -| -* `pactbroker.host` (plugin prop) - -* `stubrunner.properties.pactbroker.host` (system prop) - -* `STUBRUNNER_PROPERTIES_PACTBROKER_HOST` (env prop) -|Host from URL passed to `repositoryRoot` -|The URL of the Pact Broker. - -| -* `pactbroker.port` (plugin prop) - -* `stubrunner.properties.pactbroker.port` (system prop) - -* `STUBRUNNER_PROPERTIES_PACTBROKER_PORT` (env prop) -|Port from URL passed to `repositoryRoot` -|The port of Pact Broker. - -| -* `pactbroker.protocol` (plugin prop) - -* `stubrunner.properties.pactbroker.protocol` (system prop) - -* `STUBRUNNER_PROPERTIES_PACTBROKER_PROTOCOL` (env prop) -|Protocol from URL passed to `repositoryRoot` -|The protocol of Pact Broker. - -| -* `pactbroker.tags` (plugin prop) - -* `stubrunner.properties.pactbroker.tags` (system prop) - -* `STUBRUNNER_PROPERTIES_PACTBROKER_TAGS` (env prop) -|Version of the stub, or `latest` if version is `+` -|The tags that should be used to fetch the stub. - -| -* `pactbroker.auth.scheme` (plugin prop) - -* `stubrunner.properties.pactbroker.auth.scheme` (system prop) - -* `STUBRUNNER_PROPERTIES_PACTBROKER_AUTH_SCHEME` (env prop) -|`Basic` -|The kind of authentication that should be used to connect to the Pact Broker. - -| -* `pactbroker.auth.username` (plugin prop) - -* `stubrunner.properties.pactbroker.auth.username` (system prop) - -* `STUBRUNNER_PROPERTIES_PACTBROKER_AUTH_USERNAME` (env prop) -|The username passed to `contractsRepositoryUsername` (Maven) or `contractRepository.username` (Gradle) -|The username to use when connecting to the Pact Broker. - -| -* `pactbroker.auth.password` (plugin prop) - -* `stubrunner.properties.pactbroker.auth.password` (system prop) - -* `STUBRUNNER_PROPERTIES_PACTBROKER_AUTH_PASSWORD` (env prop) -|The password passed to `contractsRepositoryPassword` (Maven) or `contractRepository.password` (Gradle) -|The password to use when connecting to the Pact Broker. - -| -* `pactbroker.provider-name-with-group-id` (plugin prop) - -* `stubrunner.properties.pactbroker.provider-name-with-group-id` (system prop) - -* `STUBRUNNER_PROPERTIES_PACTBROKER_PROVIDER_NAME_WITH_GROUP_ID` (env prop) -|false -|When `true`, the provider name is a combination of `groupId:artifactId`. If `false`, only `artifactId` is used. -|==== - -[[how-to-pact-consumer]] -=== Flow: Consumer Contract Approach with Pact Broker on the Consumer Side - -The consumer uses the Pact framework to generate Pact files. The -Pact files are sent to the Pact Broker. You can find an example of such a setup -https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/{samples_branch}/consumer_pact[here]. - -[[how-to-pact-producer]] -=== Flow: Consumer Contract Approach with Pact Broker on the Producer Side - -For the producer to use the Pact files from the Pact Broker, we can reuse the -same mechanism we use for external contracts. We route Spring Cloud Contract -to use the Pact implementation with the URL that contains -the `pact://` protocol. You can pass the URL to the -Pact Broker. You can find an example of such a setup -https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/{samples_branch}/producer_pact[here]. -The following listing shows the configuration details for both Maven and Gradle: - -==== -[source,xml,indent=0,role="primary"] -.Maven ----- - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${spring-cloud-contract.version} - true - - - - - pact://http://localhost:8085 - - - - ${project.groupId} - ${project.artifactId} - - + - - - - REMOTE - - - - - org.springframework.cloud - spring-cloud-contract-pact - ${spring-cloud-contract.version} - - - ----- - -[source,groovy,indent=0,role="secondary"] -.Gradle ----- -buildscript { - repositories { - //... - } - - dependencies { - // ... - // Don't forget to add spring-cloud-contract-pact to the classpath! - classpath "org.springframework.cloud:spring-cloud-contract-pact:${contractVersion}" - } -} - -contracts { - // When + is passed, a latest tag will be applied when fetching pacts - contractDependency { - stringNotation = "${project.group}:${project.name}:+" - } - contractRepository { - repositoryUrl = "pact://http://localhost:8085" - } - // The mode can't be classpath - contractsMode = "REMOTE" - // Base class mappings etc. -} ----- -==== - -With such a setup: - -* Pact files are downloaded from the Pact Broker. -* Spring Cloud Contract converts the Pact files into tests and stubs. -* The JAR with the stubs gets automatically created, as usual. - -[[how-to-pact-consumer-producer-contract]] -=== Flow: Producer Contract Approach with Pact on the Consumer Side - -In the scenario where you do not want to do the consumer contract approach -(for every single consumer, define the expectations) but you prefer -to do producer contracts (the producer provides the contracts and -publishes stubs), you can use Spring Cloud Contract with the -Stub Runner option. You can find an example of such a setup -https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/{samples_branch}/consumer_pact_stubrunner[here]. - -Remember to add the Stub Runner and Spring Cloud Contract Pact modules -as test dependencies. - -The following listing shows the configuration details for both Maven and Gradle: - -==== -[source,xml,indent=0,role="primary"] -.Maven ----- - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud.version} - pom - import - - - - - - - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner - test - - - org.springframework.cloud - spring-cloud-contract-pact - test - - ----- - -[source,groovy,indent=0,role="secondary"] -.Gradle ----- -dependencyManagement { - imports { - mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" - } -} - -dependencies { - //... - testCompile("org.springframework.cloud:spring-cloud-starter-contract-stub-runner") - // Don't forget to add spring-cloud-contract-pact to the classpath! - testCompile("org.springframework.cloud:spring-cloud-contract-pact") -} ----- -==== - -Next, you can pass the URL of the Pact Broker to `repositoryRoot`, prefixed -with the `pact://` protocol (for example, `pact://http://localhost:8085`), as the following -example shows: - -==== -[source,java,indent=0] ----- -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureStubRunner(stubsMode = StubRunnerProperties.StubsMode.REMOTE, - ids = "com.example:beer-api-producer-pact", - repositoryRoot = "pact://http://localhost:8085") -public class BeerControllerTest { - //Inject the port of the running stub - @StubRunnerPort("beer-api-producer-pact") int producerPort; - //... -} ----- -==== - -With such a setup: - -* Pact files are downloaded from the Pact Broker. -* Spring Cloud Contract converts the Pact files into stub definitions. -* The stub servers are started and fed with stubs. - [[how-to-debug]] == How Can I Debug the Request/Response Being Sent by the Generated Tests Client? diff --git a/docs/src/main/asciidoc/spring-cloud-contract.adoc b/docs/src/main/asciidoc/spring-cloud-contract.adoc index 7203e7798b..a73417931f 100644 --- a/docs/src/main/asciidoc/spring-cloud-contract.adoc +++ b/docs/src/main/asciidoc/spring-cloud-contract.adoc @@ -14,5 +14,5 @@ The reference documentation consists of the following sections: <> :: {project-full-name} usage examples and workflows. <> :: Contract DSL, Messaging, Spring Cloud Contract Stub Runner, and Spring Cloud Contract WireMock. <> :: Maven Plugin, Gradle Plugin, and Docker. -<> :: Stubs versioning, Pact integration, Debugging, and more. +<> :: Stubs versioning, Debugging, and more. <> :: Properties, Metadata, Configuration, Dependencies, and more. diff --git a/pom.xml b/pom.xml index b22204adc4..24533771b6 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,6 @@ 3.19.0 - 4.3.15 0.0.9 4.0.0-SNAPSHOT 4.0.0-SNAPSHOT @@ -226,36 +225,6 @@ commons-text ${commons-text.version} - - au.com.dius.pact.consumer - junit5 - ${pact.version} - - - org.apache.groovy - groovy-all - - - org.apache.groovy - groovy - - - - - au.com.dius.pact.provider - junit5 - ${pact.version} - - - org.apache.groovy - groovy-all - - - org.apache.groovy - groovy - - - com.github.jknack handlebars diff --git a/samples/standalone/dsl/http-server/pom.xml b/samples/standalone/dsl/http-server/pom.xml index aeeb2ae68d..fe4a171246 100644 --- a/samples/standalone/dsl/http-server/pom.xml +++ b/samples/standalone/dsl/http-server/pom.xml @@ -96,14 +96,6 @@ com.example.fraud - - - - org.springframework.cloud - spring-cloud-contract-pact - ${spring-cloud-contract.version} - - diff --git a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudDetectionController.java b/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudDetectionController.java index 5e3e4e91a5..bf84fc94ba 100644 --- a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudDetectionController.java +++ b/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudDetectionController.java @@ -51,11 +51,6 @@ public class FraudDetectionController { // end::initial_impl[] } - @RequestMapping(value = "/pactfraudcheck", method = PUT) - public FraudCheckResult pactFraudCheck(@RequestBody FraudCheck fraudCheck) { - return fraudCheck(fraudCheck); - } - @RequestMapping(value = "/yamlfraudcheck", method = PUT) public FraudCheckResult yamlFraudCheck(@RequestBody FraudCheck fraudCheck) { return fraudCheck(fraudCheck); diff --git a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudStatsController.java b/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudStatsController.java index 3d7aa83606..c8b7f11ca7 100644 --- a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudStatsController.java +++ b/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudStatsController.java @@ -46,11 +46,6 @@ public class FraudStatsController { return new Response(this.statsProvider.count(FraudType.ALL)); } - @GetMapping(value = "/pactfrauds") - public Response countAllPactFrauds() { - return countAllFrauds(); - } - @GetMapping(value = "/yamlfrauds") public Response countAllYamlFrauds() { return countAllFrauds(); @@ -61,11 +56,6 @@ public class FraudStatsController { return new Response(this.statsProvider.count(FraudType.DRUNKS)); } - @GetMapping(value = "/pactdrunks") - public Response countAllPactDrunks() { - return countAllDrunks(); - } - @GetMapping(value = "/yamldrunks") public Response countAllYamlDrunks() { return countAllDrunks(); @@ -101,4 +91,4 @@ class DefaultStatsProvider implements StatsProvider { public int count(FraudType fraudType) { return 0; } -} \ No newline at end of file +} diff --git a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/PactBase.java b/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/PactBase.java deleted file mode 100644 index ba6b7f5408..0000000000 --- a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/PactBase.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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 com.example.fraud; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.jupiter.api.BeforeEach; - -public class PactBase { - - @BeforeEach - 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; - } - -} diff --git a/samples/standalone/dsl/http-server/src/test/resources/contracts/pact/shouldMarkClientAsFraud.json b/samples/standalone/dsl/http-server/src/test/resources/contracts/pact/shouldMarkClientAsFraud.json deleted file mode 100644 index b4073fb820..0000000000 --- a/samples/standalone/dsl/http-server/src/test/resources/contracts/pact/shouldMarkClientAsFraud.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "provider": { - "name": "Provider" - }, - "consumer": { - "name": "Consumer" - }, - "interactions": [ - { - "description": "", - "request": { - "method": "PUT", - "path": "/pactfraudcheck", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "clientId": "1234567890", - "loanAmount": 99999 - }, - "generators": { - "body": { - "$.clientId": { - "type": "Regex", - "regex": "[0-9]{10}" - } - } - }, - "matchingRules": { - "header": { - "Content-Type": { - "matchers": [ - { - "match": "regex", - "regex": "application/json.*" - } - ], - "combine": "AND" - } - }, - "body": { - "$.clientId": { - "matchers": [ - { - "match": "regex", - "regex": "[0-9]{10}" - } - ], - "combine": "AND" - } - } - } - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json" - }, - "body": { - "fraudCheckStatus": "FRAUD", - "rejection.reason": "Amount too high" - }, - "matchingRules": { - "header": { - "Content-Type": { - "matchers": [ - { - "match": "regex", - "regex": "application/json.*" - } - ], - "combine": "AND" - } - }, - "body": { - "$.fraudCheckStatus": { - "matchers": [ - { - "match": "regex", - "regex": "FRAUD" - } - ], - "combine": "AND" - } - } - } - } - } - ], - "metadata": { - "pact-specification": { - "version": "3.0.0" - }, - "pact-jvm": { - "version": "3.5.13" - } - } -} diff --git a/samples/standalone/dsl/http-server/src/test/resources/contracts/pact/shouldMarkClientAsNotFraud.json b/samples/standalone/dsl/http-server/src/test/resources/contracts/pact/shouldMarkClientAsNotFraud.json deleted file mode 100644 index ab3d88211c..0000000000 --- a/samples/standalone/dsl/http-server/src/test/resources/contracts/pact/shouldMarkClientAsNotFraud.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "provider": { - "name": "Provider" - }, - "consumer": { - "name": "Consumer" - }, - "interactions": [ - { - "description": "", - "request": { - "method": "PUT", - "path": "/pactfraudcheck", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "clientId": "1234567890", - "loanAmount": 123.123 - } - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json" - }, - "body": { - "fraudCheckStatus": "OK", - "rejection.reason": null - } - } - } - ], - "metadata": { - "pact-specification": { - "version": "2.0.0" - }, - "pact-jvm": { - "version": "2.4.18" - } - } -} diff --git a/samples/standalone/dsl/http-server/src/test/resources/contracts/pact/shouldReturnDrunksStats.json b/samples/standalone/dsl/http-server/src/test/resources/contracts/pact/shouldReturnDrunksStats.json deleted file mode 100644 index e5530d31c9..0000000000 --- a/samples/standalone/dsl/http-server/src/test/resources/contracts/pact/shouldReturnDrunksStats.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "provider": { - "name": "Provider" - }, - "consumer": { - "name": "Consumer" - }, - "interactions": [ - { - "description": "", - "request": { - "method": "GET", - "path": "/pactdrunks" - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json" - }, - "body": { - "count": 100 - } - } - } - ], - "metadata": { - "pact-specification": { - "version": "2.0.0" - }, - "pact-jvm": { - "version": "2.4.18" - } - } -} diff --git a/samples/standalone/dsl/http-server/src/test/resources/contracts/pact/shouldReturnFraudStats.json b/samples/standalone/dsl/http-server/src/test/resources/contracts/pact/shouldReturnFraudStats.json deleted file mode 100644 index 8fb16e519e..0000000000 --- a/samples/standalone/dsl/http-server/src/test/resources/contracts/pact/shouldReturnFraudStats.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "provider": { - "name": "Provider" - }, - "consumer": { - "name": "Consumer" - }, - "interactions": [ - { - "description": "", - "request": { - "method": "GET", - "path": "/pactfrauds" - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json" - }, - "body": { - "count": 200 - } - } - } - ], - "metadata": { - "pact-specification": { - "version": "2.0.0" - }, - "pact-jvm": { - "version": "2.4.18" - } - } -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/Contract.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/Contract.java index 692fc887e8..4d1777a689 100644 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/Contract.java +++ b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/Contract.java @@ -162,7 +162,6 @@ public class Contract { throw new IllegalStateException("Status is missing for HTTP contract"); } } - // Can't assert messaging part cause Pact doesn't require destinations it seems } /** diff --git a/spring-cloud-contract-dependencies/pom.xml b/spring-cloud-contract-dependencies/pom.xml index e1600a856a..1d4e9b4d1d 100644 --- a/spring-cloud-contract-dependencies/pom.xml +++ b/spring-cloud-contract-dependencies/pom.xml @@ -55,11 +55,6 @@ spring-cloud-contract-converters ${project.version} - - org.springframework.cloud - spring-cloud-contract-pact - ${project.version} - org.springframework.cloud spring-cloud-contract-stub-runner diff --git a/spring-cloud-contract-tools/pom.xml b/spring-cloud-contract-tools/pom.xml index 82ff62d5b4..71bb36afc9 100644 --- a/spring-cloud-contract-tools/pom.xml +++ b/spring-cloud-contract-tools/pom.xml @@ -19,7 +19,6 @@ spring-cloud-contract-converters - spring-cloud-contract-pact spring-cloud-contract-maven-plugin spring-cloud-contract-gradle-plugin spring-cloud-contract-gradle-portal-plugin diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml index 34aa42034e..94506a6480 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml +++ b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml @@ -378,11 +378,6 @@ assertj-core test - - org.springframework.cloud - spring-cloud-contract-pact - test - org.apache.maven.plugin-testing maven-plugin-testing-harness diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/PluginUnitTest.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/PluginUnitTest.java index cc5e45d582..aad8f88abf 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/PluginUnitTest.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/PluginUnitTest.java @@ -22,8 +22,6 @@ import org.codehaus.plexus.util.xml.Xpp3Dom; import org.junit.Ignore; import org.junit.Test; -import org.springframework.util.StringUtils; - import static java.nio.charset.Charset.defaultCharset; import static org.apache.commons.io.FileUtils.readFileToString; import static org.apache.maven.plugin.testing.MojoParameters.newParameter; @@ -309,21 +307,6 @@ public class PluginUnitTest extends AbstractMojoTest { "target/stubs/META-INF/org.springframework.cloud.verifier.sample/common-repo/0.1/contracts/pom.xml"); } - @Test - public void shouldGenerateContractTestsForPactAndMaintainIndents() throws Exception { - File basedir = getBasedir("pact"); - - executeMojo(basedir, "generateTests", defaultPackageForTests()); - - assertFilesPresent(basedir, - "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/ContractVerifierTest.java"); - File test = new File(basedir, - "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/ContractVerifierTest.java"); - String testContents = readFileToString(test, defaultCharset()); - int countOccurrencesOf = StringUtils.countOccurrencesOf(testContents, "\t\tMockMvcRequestSpecification"); - then(countOccurrencesOf).isEqualTo(4); - } - @Test public void shouldRunPushStubsToScm() throws Exception { File basedir = getBasedir("git-basic-remote-contracts"); diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pact/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pact/pom.xml deleted file mode 100644 index c426e07ba6..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pact/pom.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - 4.0.0 - - org.springframework.cloud.verifier.sample - sample-pact-project - 0.1 - - - 2.0.0.BUILD-SNAPSHOT - - - - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - - com.example.FooBase - - - .*com.* - com.example.TestBase - - - - - - org.springframework.cloud - spring-cloud-contract-pact - ${spring.cloud.contract.version} - - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pact/src/test/resources/contracts/shouldMarkClientAsFraud.json b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pact/src/test/resources/contracts/shouldMarkClientAsFraud.json deleted file mode 100644 index b2bbb9d65e..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pact/src/test/resources/contracts/shouldMarkClientAsFraud.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "provider": { - "name": "Provider" - }, - "consumer": { - "name": "Consumer" - }, - "interactions": [ - { - "description": "", - "request": { - "method": "PUT", - "path": "/fraudcheck", - "headers": { - "Content-Type": "application/vnd.fraud.v1+json" - }, - "body": { - "clientId": "1234567890", - "loanAmount": 99999 - } - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/vnd.fraud.v1+json;charset=UTF-8" - }, - "body": { - "fraudCheckStatus": "FRAUD", - "rejectionReason": "Amount too high" - } - } - } - ], - "metadata": { - "pact-specification": { - "version": "2.0.0" - }, - "pact-jvm": { - "version": "2.4.18" - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.json b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.json deleted file mode 100644 index 0d1825a800..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "provider": { - "name": "Provider" - }, - "consumer": { - "name": "Consumer" - }, - "interactions": [ - { - "description": "", - "request": { - "method": "PUT", - "path": "/fraudcheck", - "headers": { - "Content-Type": "application/vnd.fraud.v1+json" - }, - "body": { - "clientId": "1234567890", - "loanAmount": 123.123 - } - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/vnd.fraud.v1+json;charset=UTF-8" - }, - "body": { - "fraudCheckStatus": "OK", - "rejectionReason": null - } - } - } - ], - "metadata": { - "pact-specification": { - "version": "2.0.0" - }, - "pact-jvm": { - "version": "2.4.18" - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pact/src/test/resources/contracts/shouldReturnDrunksStats.json b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pact/src/test/resources/contracts/shouldReturnDrunksStats.json deleted file mode 100644 index e53984d8f9..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pact/src/test/resources/contracts/shouldReturnDrunksStats.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "provider": { - "name": "Provider" - }, - "consumer": { - "name": "Consumer" - }, - "interactions": [ - { - "description": "", - "request": { - "method": "GET", - "path": "/drunks" - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/vnd.fraud.v1+json;charset=UTF-8" - }, - "body": { - "count": 100 - } - } - } - ], - "metadata": { - "pact-specification": { - "version": "2.0.0" - }, - "pact-jvm": { - "version": "2.4.18" - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pact/src/test/resources/contracts/shouldReturnFraudStats.json b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pact/src/test/resources/contracts/shouldReturnFraudStats.json deleted file mode 100644 index 3cf184c343..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pact/src/test/resources/contracts/shouldReturnFraudStats.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "provider": { - "name": "Provider" - }, - "consumer": { - "name": "Consumer" - }, - "interactions": [ - { - "description": "", - "request": { - "method": "GET", - "path": "/frauds" - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/vnd.fraud.v1+json;charset=UTF-8" - }, - "body": { - "count": 200 - } - } - } - ], - "metadata": { - "pact-specification": { - "version": "2.0.0" - }, - "pact-jvm": { - "version": "2.4.18" - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-pact/pom.xml deleted file mode 100644 index 3e40bc8ebf..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/pom.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-tools - 4.0.0-SNAPSHOT - .. - - spring-cloud-contract-pact - jar - Spring Cloud Contract Pact - Spring Cloud Contract Pact - - - org.springframework - spring-context - - - org.springframework.cloud - spring-cloud-contract-converters - - - org.springframework.cloud - spring-cloud-contract-stub-runner - - - org.springframework.boot - spring-boot-starter-logging - - - org.apache.groovy - groovy - - - org.apache.groovy - groovy-nio - - - au.com.dius.pact.consumer - junit5 - - - au.com.dius.pact.provider - junit5 - - - org.springframework.boot - spring-boot-autoconfigure-processor - true - - - org.spockframework - spock-core - test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.cloud - spring-cloud-contract-wiremock - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - - addSources - addTestSources - generateStubs - compile - generateTestStubs - compileTests - removeStubs - removeTestStubs - - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/stubrunner/PactStubDownloaderBuilder.java b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/stubrunner/PactStubDownloaderBuilder.java deleted file mode 100644 index 525a120db5..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/stubrunner/PactStubDownloaderBuilder.java +++ /dev/null @@ -1,467 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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.stubrunner; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.lang.annotation.Annotation; -import java.net.URI; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import au.com.dius.pact.core.model.Pact; -import au.com.dius.pact.core.model.PactSpecVersion; -import au.com.dius.pact.core.support.expressions.SystemPropertyResolver; -import au.com.dius.pact.core.support.expressions.ValueResolver; -import au.com.dius.pact.provider.junitsupport.loader.PactBroker; -import au.com.dius.pact.provider.junitsupport.loader.PactBrokerAuth; -import au.com.dius.pact.provider.junitsupport.loader.PactBrokerLoader; -import au.com.dius.pact.provider.junitsupport.loader.PactLoader; -import au.com.dius.pact.provider.junitsupport.loader.VersionSelector; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.cloud.contract.verifier.spec.pact.PactContractConverter; -import org.springframework.core.io.AbstractResource; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; -import org.springframework.lang.Nullable; -import org.springframework.util.StringUtils; - -/** - * Allows downloading of Pact files from the Pact Broker. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @since 2.0.0 - */ -public final class PactStubDownloaderBuilder implements StubDownloaderBuilder { - - private static final List ACCEPTABLE_PROTOCOLS = Collections.singletonList("pact"); - - /** - * Does any of the accepted protocols matches the URL of the repository. - * @param url - of the repository - * @return {@code true} if the protocol is accepted - */ - private static boolean isProtocolAccepted(String url) { - return ACCEPTABLE_PROTOCOLS.stream().anyMatch(url::startsWith); - } - - @Override - public StubDownloader build(StubRunnerOptions stubRunnerOptions) { - if (stubRunnerOptions.getStubsMode() == StubRunnerProperties.StubsMode.CLASSPATH - || stubRunnerOptions.getStubRepositoryRoot() == null) { - return null; - } - Resource resource = stubRunnerOptions.getStubRepositoryRoot(); - if (!(resource instanceof PactResource)) { - return null; - } - return new PactStubDownloader(stubRunnerOptions); - } - - @Override - public Resource resolve(String location, ResourceLoader resourceLoader) { - if (!StringUtils.hasText(location) || !isProtocolAccepted(location)) { - return null; - } - return new PactResource(location); - } - -} - -class PactResource extends AbstractResource { - - private final String rawLocation; - - PactResource(String location) { - this.rawLocation = location; - } - - @Override - public String getDescription() { - return this.rawLocation; - } - - @Override - public InputStream getInputStream() { - return null; - } - - @Override - public URI getURI() { - return URI.create(this.rawLocation); - } - -} - -class PactStubDownloader implements StubDownloader { - - private static final String TEMP_DIR_PREFIX = "pact"; - - private static final Log log = LogFactory.getLog(PactStubDownloader.class); - - // Preloading class for the shutdown hook not to throw ClassNotFound - private static final Class CLAZZ = TemporaryFileStorage.class; - - private static final String ARTIFICIAL_NAME_ENDING_WITH_GROOVY = "name.groovy"; - - private static final String PROVIDER_NAME_WITH_GROUP_ID = "pactbroker.provider-name-with-group-id"; - - private final StubRunnerOptions stubRunnerOptions; - - private final boolean deleteStubsAfterTest; - - private final ObjectMapper objectMapper; - - PactStubDownloader(StubRunnerOptions stubRunnerOptions) { - this.stubRunnerOptions = stubRunnerOptions; - this.objectMapper = new ObjectMapper(); - this.deleteStubsAfterTest = stubRunnerOptions.isDeleteStubsAfterTest(); - registerShutdownHook(); - } - - @Override - public Map.Entry downloadAndUnpackStubJar(StubConfiguration stubConfiguration) { - String version = stubConfiguration.version; - final FromPropsThenFromSysEnv resolver = new FromPropsThenFromSysEnv(this.stubRunnerOptions); - List tags = tags(version, resolver); - try { - PactLoader loader = pactBrokerLoader(resolver, tags); - String providerName = providerName(stubConfiguration); - List pacts = loader.load(providerName); - if (pacts.isEmpty()) { - if (log.isWarnEnabled()) { - log.warn("No pact definitions found for provider [" + providerName + "]"); - } - return null; - } - File tmpDirWhereStubsWillBeUnzipped = TemporaryFileStorage.createTempDir(TEMP_DIR_PREFIX); - // make the groupid / artifactid folders - String coordinatesFolderName = stubConfiguration.getGroupId().replace(".", File.separator) + File.separator - + stubConfiguration.getArtifactId(); - File contractsFolder = new File(tmpDirWhereStubsWillBeUnzipped, - coordinatesFolderName + File.separator + "contracts"); - File mappingsFolder = new File(tmpDirWhereStubsWillBeUnzipped, - coordinatesFolderName + File.separator + "mappings"); - boolean createdContractsDirs = contractsFolder.mkdirs(); - boolean createdMappingsDirs = mappingsFolder.mkdirs(); - if (!createdContractsDirs || !createdMappingsDirs) { - throw new IllegalStateException("Failed to create mandatory [contracts] or [mappings] folders under [" - + coordinatesFolderName + "]"); - } - storePacts(providerName, pacts, contractsFolder, mappingsFolder); - return new AbstractMap.SimpleEntry<>(stubConfiguration, tmpDirWhereStubsWillBeUnzipped); - } - catch (IOException e) { - throw new IllegalStateException(e); - } - } - - private void storePacts(String providerName, List pacts, File contractsFolder, File mappingsFolder) { - for (int i = 0; i < pacts.size(); i++) { - String json = toJson(pacts.get(i).toMap(PactSpecVersion.V3)); - File file = new File(contractsFolder, i + "_" + providerName.replace(":", "_") + "_pact.json"); - storeFile(file.toPath(), json.getBytes()); - try { - storeMapping(mappingsFolder, file); - } - catch (Exception e) { - log.warn("Exception occurred while trying to store the mapping", e); - } - } - } - - private void storeMapping(File mappingsFolder, File file) { - Collection contracts = new PactContractConverter().convertFrom(file); - if (log.isDebugEnabled()) { - log.debug("Converted pact file [" + file + "] to [" + contracts.size() + "] contracts"); - } - MappingGenerator.toMappings(file, contracts, mappingsFolder); - } - - private Path storeFile(Path path, byte[] contents) { - try { - Path storedPath = Files.write(path, contents); - if (log.isDebugEnabled()) { - log.debug("Stored file [" + path + "]"); - } - return storedPath; - } - catch (IOException e) { - throw new IllegalStateException(e); - } - } - - private String providerName(StubConfiguration stubConfiguration) { - boolean providerNameWithGroupId = Boolean.parseBoolean(StubRunnerPropertyUtils - .getProperty(this.stubRunnerOptions.getProperties(), PROVIDER_NAME_WITH_GROUP_ID)); - if (providerNameWithGroupId) { - return stubConfiguration.getGroupId() + ":" + stubConfiguration.getArtifactId(); - } - return stubConfiguration.getArtifactId(); - } - - PactLoader pactBrokerLoader(ValueResolver resolver, List tags) throws IOException { - Resource repo = this.stubRunnerOptions.getStubRepositoryRoot(); - String schemeSpecificPart = schemeSpecificPart(repo.getURI()); - URI pactBrokerUrl = URI.create(schemeSpecificPart); - String stubRunnerUsername = this.stubRunnerOptions.getUsername() != null ? this.stubRunnerOptions.getUsername() - : ""; - String stubRunnerPassword = this.stubRunnerOptions.getPassword() != null ? this.stubRunnerOptions.getPassword() - : ""; - return new PactBrokerLoader(new PactBroker() { - - @Override - public Class annotationType() { - return PactBroker.class; - } - - @Override - public String url() { - return resolver.resolveValue("pactbroker.url", - pactBrokerUrl.getScheme() + "://" + pactBrokerUrl.getHost() + ":" + pactBrokerUrl.getPort()); - } - - @Override - @Deprecated - public String host() { - return resolver.resolveValue("pactbroker.host", pactBrokerUrl.getHost()); - } - - @Override - @Deprecated - public String port() { - return resolver.resolveValue("pactbroker.port", String.valueOf(pactBrokerUrl.getPort())); - } - - @Override - @Deprecated - public String scheme() { - return resolver.resolveValue("pactbroker.protocol", pactBrokerUrl.getScheme()); - } - - @Override - @Deprecated - public String[] tags() { - return new String[0]; - } - - @Override - public VersionSelector[] consumerVersionSelectors() { - return new VersionSelector[] { new VersionSelector() { - - @Override - public Class annotationType() { - return VersionSelector.class; - } - - @Override - public String tag() { - return resolver.resolveValue("pactbroker.consumerversionselectors.tags", ""); - } - - @Override - public String latest() { - return resolver.resolveValue("pactbroker.consumerversionselectors.latest", "true"); - } - - @Override - public String consumer() { - return resolver.resolveValue("pactbroker.consumers", ""); - } - - @Override - public String fallbackTag() { - return resolver.resolveValue("pactbroker.fallbacktag", ""); - } - } }; - } - - @Override - public String[] consumers() { - return new String[] { resolver.resolveValue("pactbroker.consumers", "") }; - } - - @Override - public PactBrokerAuth authentication() { - return new PactBrokerAuth() { - @Override - public Class annotationType() { - return PactBrokerAuth.class; - } - - @Override - public String username() { - return resolver.resolveValue("pactbroker.auth.username", stubRunnerUsername); - } - - @Override - public String password() { - return resolver.resolveValue("pactbroker.auth.password", stubRunnerPassword); - } - - @Override - public String token() { - return resolver.resolveValue("pactbroker.auth.token", ""); - } - }; - } - - @Override - public Class valueResolver() { - return SystemPropertyResolver.class; - } - - @Override - public String enablePendingPacts() { - return resolver.resolveValue("pactbroker.enablePending", "false"); - } - - @Override - public String[] providerTags() { - return resolver.resolveValue("pactbroker.providerTags", "").split(","); - } - - @Override - public String providerBranch() { - return resolver.resolveValue("pactbroker.providerBranch", ""); - } - - @Override - public String includeWipPactsSince() { - return resolver.resolveValue("pactbroker.includeWipPactsSince", ""); - } - - @Override - public String enableInsecureTls() { - return resolver.resolveValue("pactbroker.enableInsecureTls", "false"); - } - }); - } - - private String schemeSpecificPart(URI uri) { - String part = uri.getSchemeSpecificPart(); - if (!StringUtils.hasText(part)) { - return part; - } - return part.startsWith("//") ? part.substring(2) : part; - } - - private List tags(String version, ValueResolver resolver) { - String defaultTag = StubConfiguration.DEFAULT_VERSION.equals(version) ? "latest" : version; - return new ArrayList<>(Arrays.asList( - StringUtils.commaDelimitedListToStringArray(resolver.resolveValue("pactbroker.tags", defaultTag)))); - } - - private String toJson(Map map) { - try { - return this.objectMapper.writeValueAsString(map); - } - catch (JsonProcessingException e) { - throw new IllegalStateException(e); - } - } - - private void registerShutdownHook() { - Runtime.getRuntime().addShutdownHook( - new Thread(() -> TemporaryFileStorage.cleanup(PactStubDownloader.this.deleteStubsAfterTest))); - } - -} - -class FromPropsThenFromSysEnv implements ValueResolver { - - final SystemPropertyResolver resolver = SystemPropertyResolver.INSTANCE; - - StubRunnerOptions options; - - FromPropsThenFromSysEnv(StubRunnerOptions options) { - this.options = options; - } - - @Override - public String resolveValue(String expression) { - return doResolve(expression, null); - } - - @Nullable - private String doResolve(String expression, @Nullable String defaultValue) { - PropertyValueTuple tuple = new PropertyValueTuple(expression).invoke(); - String propertyName = tuple.getPropertyName(); - String property = StubRunnerPropertyUtils.getProperty(this.options.getProperties(), propertyName); - if (StringUtils.hasText(property)) { - return property; - } - return this.resolver.resolveValue(expression, defaultValue); - } - - @Override - public boolean propertyDefined(String property) { - PropertyValueTuple tuple = new PropertyValueTuple(property).invoke(); - String propertyName = tuple.getPropertyName(); - boolean hasProperty = StubRunnerPropertyUtils.hasProperty(this.options.getProperties(), propertyName); - if (hasProperty) { - return true; - } - return this.resolver.propertyDefined(property); - } - - @Nullable - @Override - public String resolveValue(String expression, String defaultValue) { - return doResolve(expression, defaultValue); - } - -} - -// taken from pact - -// au.com.dius.pact.provider.junit.sysprops.SystemPropertyResolver.PropertyValueTuple -class PropertyValueTuple { - - private String propertyName; - - PropertyValueTuple(String property) { - this.propertyName = property; - } - - String getPropertyName() { - return this.propertyName; - } - - PropertyValueTuple invoke() { - if (this.propertyName.contains(":")) { - String[] kv = org.apache.commons.lang3.StringUtils.splitPreserveAllTokens(this.propertyName, ':'); - this.propertyName = kv[0]; - } - return this; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/BodyConverter.java b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/BodyConverter.java deleted file mode 100644 index fb3d6f040c..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/BodyConverter.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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.spec.pact; - -import java.io.IOException; -import java.util.Collection; -import java.util.Map; -import java.util.function.Function; -import java.util.regex.Pattern; - -import au.com.dius.pact.consumer.dsl.DslPart; -import au.com.dius.pact.consumer.dsl.PactDslJsonArray; -import au.com.dius.pact.consumer.dsl.PactDslJsonBody; -import au.com.dius.pact.core.model.OptionalBody; -import au.com.dius.pact.core.model.Request; -import au.com.dius.pact.core.model.Response; -import au.com.dius.pact.core.model.generators.Generator; -import au.com.dius.pact.core.model.messaging.Message; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.jayway.jsonpath.Configuration; -import com.jayway.jsonpath.internal.EvaluationContext; -import com.jayway.jsonpath.internal.Path; -import com.jayway.jsonpath.internal.path.PathCompiler; -import com.jayway.jsonpath.spi.json.JacksonJsonProvider; -import groovy.lang.GString; -import org.apache.commons.lang3.StringUtils; - -import org.springframework.cloud.contract.spec.internal.ClientDslProperty; -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.ServerDslProperty; -import org.springframework.cloud.contract.verifier.util.ContentUtils; - -/** - * @author Tim Ysewyn - * @author Stessy Delcroix - * @since 2.0.0 - */ -final class BodyConverter { - - private static final ObjectMapper OBJECT_MAPPER = ObjectMapperFactory.INSTANCE.getMapper(); - - private BodyConverter() { - - } - - static DslPart toPactBody(DslProperty dslProperty, Function, Object> dslPropertyValueExtractor) { - return traverse(dslProperty, null, dslPropertyValueExtractor); - } - - private static DslPart traverse(Object value, DslPart parent, - Function, Object> dslPropertyValueExtractor) { - boolean isRoot = parent == null; - Object v = value; - if (v instanceof DslProperty) { - v = dslPropertyValueExtractor.apply((DslProperty) v); - } - if (v instanceof GString) { - v = ContentUtils.extractValue((GString) v, dslPropertyValueExtractor); - } - if (v instanceof String) { - String stringValue = ((String) v).trim(); - if (StringUtils.startsWith(stringValue, "{") && StringUtils.endsWith(stringValue, "}")) { - try { - v = OBJECT_MAPPER.readValue(stringValue, Object.class); - } - catch (JsonProcessingException ex) { /* - * it wasn't a JSON string after - * all... - */ - } - } - } - DslPart p = isRoot ? createRootDslPart(v) : parent; - if (v instanceof Map) { - processMap((Map) v, (PactDslJsonBody) p, dslPropertyValueExtractor); - } - else if (v instanceof Collection) { - processCollection((Collection) v, (PactDslJsonArray) p, dslPropertyValueExtractor); - } - return p; - } - - private static DslPart createRootDslPart(Object value) { - return value instanceof Collection ? new PactDslJsonArray() : new PactDslJsonBody(); - } - - private static void processCollection(Collection values, PactDslJsonArray jsonArray, - Function, Object> dslPropertyValueExtractor) { - values.forEach(v -> { - - if (v instanceof DslProperty) { - v = dslPropertyValueExtractor.apply((DslProperty) v); - } - if (v instanceof GString) { - v = ContentUtils.extractValue((GString) v, dslPropertyValueExtractor); - } - if (v == null) { - jsonArray.nullValue(); - } - else if (v instanceof String) { - jsonArray.string((String) v); - } - else if (v instanceof Number) { - jsonArray.number((Number) v); - } - else if (v instanceof Map) { - PactDslJsonBody current = jsonArray.object(); - traverse(v, current, dslPropertyValueExtractor); - current.closeObject(); - } - else if (v instanceof Collection) { - PactDslJsonArray current = jsonArray.array(); - traverse(v, current, dslPropertyValueExtractor); - current.closeArray(); - } - }); - } - - private static void processMap(Map values, PactDslJsonBody jsonObject, - Function, Object> dslPropertyValueExtractor) { - values.forEach((k, v) -> { - if (v instanceof DslProperty) { - v = dslPropertyValueExtractor.apply((DslProperty) v); - } - if (v instanceof GString) { - v = ContentUtils.extractValue((GString) v, dslPropertyValueExtractor); - } - if (v == null) { - jsonObject.nullValue(k); - } - else if (v instanceof Boolean) { - jsonObject.booleanValue(k, (Boolean) v); - } - else if (v instanceof String) { - jsonObject.stringType(k, (String) v); - } - else if (v instanceof Number) { - jsonObject.numberValue(k, (Number) v); - } - else if (v instanceof Map) { - PactDslJsonBody current = jsonObject.object(k); - traverse(v, current, dslPropertyValueExtractor); - current.closeObject(); - } - else if (v instanceof Collection) { - PactDslJsonArray current = jsonObject.array(k); - traverse(v, current, dslPropertyValueExtractor); - current.closeArray(); - } - }); - } - - static Object toSCCBody(Request request) { - Object body = parseBody(request.getBody()); - if (request.getGenerators().isNotEmpty() && request.getGenerators().getCategories() - .containsKey(au.com.dius.pact.core.model.generators.Category.BODY)) { - applyGenerators(body, - request.getGenerators().getCategories().get(au.com.dius.pact.core.model.generators.Category.BODY), - currentValue -> pattern -> generatedValue -> new DslProperty<>( - new ClientDslProperty(pattern, generatedValue), currentValue)); - } - return body; - } - - static Object toSCCBody(Response response) { - Object body = parseBody(response.getBody()); - if (response.getGenerators().isNotEmpty() && response.getGenerators().getCategories() - .containsKey(au.com.dius.pact.core.model.generators.Category.BODY)) { - applyGenerators(body, - response.getGenerators().getCategories().get(au.com.dius.pact.core.model.generators.Category.BODY), - currentValue -> pattern -> generatedValue -> new DslProperty<>(currentValue, - new ServerDslProperty(pattern, generatedValue))); - } - return body; - } - - static Object toSCCBody(Message message) { - Object body = parseBody(message.getContents()); - if (message.getGenerators().isNotEmpty() && message.getGenerators().getCategories() - .containsKey(au.com.dius.pact.core.model.generators.Category.BODY)) { - applyGenerators(body, - message.getGenerators().getCategories().get(au.com.dius.pact.core.model.generators.Category.BODY), - currentValue -> pattern -> generatedValue -> new DslProperty<>( - new ClientDslProperty(pattern, generatedValue), currentValue)); - } - return body; - } - - private static Object parseBody(OptionalBody optionalBody) { - if (optionalBody.isPresent()) { - try { - return OBJECT_MAPPER.readValue(optionalBody.getValue(), Object.class); - } - catch (IOException e) { - throw new RuntimeException("Body could not be read", e); - } - } - else { - return optionalBody.getValue(); - } - } - - private static void applyGenerators(Object body, Map generatorsPerPath, - Function>>> dslPropertyProvider) { - Configuration configuration = Configuration.builder().jsonProvider(new JacksonJsonProvider(OBJECT_MAPPER)) - .build(); - generatorsPerPath.forEach((path, generator) -> { - Path compiledPath = PathCompiler.compile(path); - EvaluationContext evaluationContext = compiledPath.evaluate(body, body, configuration, true); - evaluationContext.updateOperations().forEach(pathRef -> { - pathRef.convert(((currentValue, config) -> ValueGeneratorConverter.convert(generator, - (pattern, generatedValue) -> dslPropertyProvider.apply(pattern).apply(generatedValue) - .apply(currentValue))), - configuration); - }); - }); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/MatchingRulesConverter.java b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/MatchingRulesConverter.java deleted file mode 100644 index 75aaec0a0c..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/MatchingRulesConverter.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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.spec.pact; - -import au.com.dius.pact.core.model.matchingrules.DateMatcher; -import au.com.dius.pact.core.model.matchingrules.EqualsMatcher; -import au.com.dius.pact.core.model.matchingrules.MatchingRuleCategory; -import au.com.dius.pact.core.model.matchingrules.MaxTypeMatcher; -import au.com.dius.pact.core.model.matchingrules.MinMaxTypeMatcher; -import au.com.dius.pact.core.model.matchingrules.MinTypeMatcher; -import au.com.dius.pact.core.model.matchingrules.NullMatcher; -import au.com.dius.pact.core.model.matchingrules.NumberTypeMatcher; -import au.com.dius.pact.core.model.matchingrules.RegexMatcher; -import au.com.dius.pact.core.model.matchingrules.TimeMatcher; -import au.com.dius.pact.core.model.matchingrules.TimestampMatcher; -import au.com.dius.pact.core.model.matchingrules.TypeMatcher; - -import org.springframework.cloud.contract.spec.internal.BodyMatchers; -import org.springframework.cloud.contract.spec.internal.MatchingType; -import org.springframework.cloud.contract.spec.internal.RegexPatterns; - -/** - * @author Tim Ysewyn - * @author Stessy Delcroix - * @since 2.0.0 - */ -final class MatchingRulesConverter { - - private MatchingRulesConverter() { - } - - static MatchingRuleCategory matchingRulesForBody(BodyMatchers bodyMatchers) { - return matchingRulesFor("body", bodyMatchers); - } - - private static MatchingRuleCategory matchingRulesFor(String categoryName, BodyMatchers bodyMatchers) { - MatchingRuleCategory category = new MatchingRuleCategory(categoryName); - bodyMatchers.matchers().forEach((b) -> { - String key = getMatcherKey(b.path()); - MatchingType matchingType = b.matchingType(); - switch (matchingType) { - case NULL: - category.addRule(key, NullMatcher.INSTANCE); - break; - case EQUALITY: - category.addRule(key, EqualsMatcher.INSTANCE); - break; - case TYPE: - if (b.minTypeOccurrence() != null && b.maxTypeOccurrence() != null) { - category.addRule(key, new MinMaxTypeMatcher(b.minTypeOccurrence(), b.maxTypeOccurrence())); - } - else if (b.minTypeOccurrence() != null) { - category.addRule(key, new MinTypeMatcher(b.minTypeOccurrence())); - } - else if (b.maxTypeOccurrence() != null) { - category.addRule(key, new MaxTypeMatcher(b.maxTypeOccurrence())); - } - else { - category.addRule(key, TypeMatcher.INSTANCE); - } - break; - case DATE: - category.addRule(key, new DateMatcher()); - break; - case TIME: - category.addRule(key, new TimeMatcher()); - break; - case TIMESTAMP: - category.addRule(key, new TimestampMatcher()); - break; - case REGEX: - String pattern = b.value().toString(); - if (pattern.equals(RegexPatterns.number().pattern())) { - category.addRule(key, new NumberTypeMatcher(NumberTypeMatcher.NumberType.NUMBER)); - } - else if (pattern.equals(RegexPatterns.anInteger().pattern())) { - category.addRule(key, new NumberTypeMatcher(NumberTypeMatcher.NumberType.INTEGER)); - } - else if (pattern.equals(RegexPatterns.aDouble().pattern())) { - category.addRule(key, new NumberTypeMatcher(NumberTypeMatcher.NumberType.DECIMAL)); - } - else { - category.addRule(key, new RegexMatcher(pattern)); - } - break; - default: - break; - } - }); - return category; - } - - private static String getMatcherKey(String path) { - return path.startsWith("$") ? path.substring(1) : path; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/MessagePactCreator.java b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/MessagePactCreator.java deleted file mode 100644 index e27ecb5b95..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/MessagePactCreator.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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.spec.pact; - -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -import au.com.dius.pact.consumer.MessagePactBuilder; -import au.com.dius.pact.consumer.dsl.DslPart; -import au.com.dius.pact.core.model.messaging.MessagePact; -import groovy.lang.GString; -import org.apache.commons.collections.CollectionUtils; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.Header; -import org.springframework.cloud.contract.spec.internal.Headers; -import org.springframework.cloud.contract.spec.internal.Input; -import org.springframework.cloud.contract.spec.internal.OutputMessage; -import org.springframework.cloud.contract.verifier.util.ContentUtils; - -/** - * Creator of {@link MessagePact} instances. - * - * @author Tim Ysewyn - * @author Stessy Delcroix - * @since 2.0.0 - */ -class MessagePactCreator { - - private static final Function, Object> clientValueExtractor = DslProperty::getClientValue; - - MessagePact createFromContract(List contracts) { - if (CollectionUtils.isEmpty(contracts)) { - return null; - } - Names names = NamingUtil.name(contracts.get(0)); - MessagePactBuilder pactBuilder = new MessagePactBuilder().consumer(names.getConsumer()) - .hasPactWith(names.getProducer()); - - for (Contract contract : contracts) { - pactBuilder = pactBuilder.given(getGiven(contract.getInput())).expectsToReceive(getOutcome(contract)); - if (contract.getOutputMessage() != null) { - OutputMessage message = contract.getOutputMessage(); - if (message.getBody() != null) { - DslPart pactResponseBody = BodyConverter.toPactBody(message.getBody(), clientValueExtractor); - if (message.getBodyMatchers() != null) { - pactResponseBody - .setMatchers(MatchingRulesConverter.matchingRulesForBody(message.getBodyMatchers())); - } - pactResponseBody - .setGenerators(ValueGeneratorConverter.extract(message, DslProperty::getServerValue)); - pactBuilder = pactBuilder.withContent(pactResponseBody); - } - if (message.getHeaders() != null) { - pactBuilder = pactBuilder.withMetadata(getMetadata(message.getHeaders())); - } - } - } - return pactBuilder.toPact(); - } - - private String getGiven(Input input) { - if (input.getTriggeredBy() != null) { - return input.getTriggeredBy().getExecutionCommand(); - } - else { - return ""; - } - } - - private String getOutcome(Contract contract) { - if (contract.getOutputMessage() != null) { - OutputMessage message = contract.getOutputMessage(); - return "message sent to " + clientValueExtractor.apply(message.getSentTo()); - } - else { - return "assert that " + contract.getInput().getAssertThat().getExecutionCommand(); - } - } - - private Map getMetadata(Headers headers) { - return headers.getEntries().stream().collect(Collectors.toMap(Header::getName, this::extractValue)); - } - - private String extractValue(Object value) { - Object v = value; - if (v instanceof DslProperty) { - v = clientValueExtractor.apply((DslProperty) v); - } - if (v instanceof GString) { - v = ContentUtils.extractValue((GString) v, clientValueExtractor); - } - if (v instanceof String) { - return (String) v; - } - else { - return v.toString(); - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/MessagingSCContractCreator.java b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/MessagingSCContractCreator.java deleted file mode 100644 index fedc9769cb..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/MessagingSCContractCreator.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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.spec.pact; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -import au.com.dius.pact.core.model.matchingrules.DateMatcher; -import au.com.dius.pact.core.model.matchingrules.MatchingRule; -import au.com.dius.pact.core.model.matchingrules.MatchingRuleCategory; -import au.com.dius.pact.core.model.matchingrules.MaxTypeMatcher; -import au.com.dius.pact.core.model.matchingrules.MinMaxTypeMatcher; -import au.com.dius.pact.core.model.matchingrules.MinTypeMatcher; -import au.com.dius.pact.core.model.matchingrules.NullMatcher; -import au.com.dius.pact.core.model.matchingrules.NumberTypeMatcher; -import au.com.dius.pact.core.model.matchingrules.RegexMatcher; -import au.com.dius.pact.core.model.matchingrules.RuleLogic; -import au.com.dius.pact.core.model.matchingrules.TimeMatcher; -import au.com.dius.pact.core.model.matchingrules.TimestampMatcher; -import au.com.dius.pact.core.model.matchingrules.TypeMatcher; -import au.com.dius.pact.core.model.messaging.Message; -import au.com.dius.pact.core.model.messaging.MessagePact; -import org.apache.commons.lang3.StringUtils; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.internal.Headers; -import org.springframework.cloud.contract.spec.internal.RegexPatterns; -import org.springframework.cloud.contract.spec.internal.ResponseBodyMatchers; -import org.springframework.cloud.contract.verifier.util.JsonPaths; -import org.springframework.cloud.contract.verifier.util.JsonToJsonPathsConverter; - -/** - * Creator of {@link Contract} instances. - * - * @author Tim Ysewyn - * @author Stessy Delcroix - * @since 2.0.0 - */ -class MessagingSCContractCreator { - - private static final String FULL_BODY = "$"; - - private static final String DESTINATION_KEY = "sentTo"; - - private static final List NON_HEADER_META_DATA = Collections.singletonList(DESTINATION_KEY); - - Collection convertFrom(MessagePact pact) { - return pact.getMessages().stream().map(message -> Contract.make(contract -> { - contract.label(message.getDescription()); - if (!message.getProviderStates().isEmpty()) { - contract.input(i -> i.triggeredBy(this.getTriggeredBy(message))); - } - - contract.outputMessage((outputMessage) -> { - if (message.getContents().isPresent()) { - outputMessage.body(BodyConverter.toSCCBody(message)); - MatchingRuleCategory bodyRules = message.getMatchingRules().rulesForCategory("body"); - if (bodyRules != null && !bodyRules.getMatchingRules().isEmpty()) { - outputMessage.bodyMatchers((responseBodyMatchers) -> outputMessageBodyMatchers(message, - bodyRules, responseBodyMatchers)); - } - } - if (!message.getMetadata().isEmpty()) { - outputMessage.headers((headers) -> outputMessageHeaders(message, headers)); - } - String dest = findDestination(message); - if (StringUtils.isNotBlank(dest)) { - outputMessage.sentTo(dest); - } - }); - })).collect(Collectors.toList()); - } - - private void outputMessageHeaders(Message message, Headers headers) { - message.getMetadata().forEach((key, value) -> { - String matchingRuleGroup = value.toString(); - if (key.equalsIgnoreCase("contentType")) { - headers.messagingContentType(matchingRuleGroup); - } - else if (!NON_HEADER_META_DATA.contains(key)) { - headers.header(key, matchingRuleGroup); - } - }); - } - - private void outputMessageBodyMatchers(Message message, MatchingRuleCategory bodyRules, - ResponseBodyMatchers responseBodyMatchers) { - bodyRules.getMatchingRules().forEach((matchingRuleKey, matchingRuleGroup) -> { - if (matchingRuleGroup.getRuleLogic() != RuleLogic.AND) { - throw new UnsupportedOperationException("Currently only the AND combination rule logic is supported"); - } - if (FULL_BODY.equals(matchingRuleKey)) { - JsonPaths jsonPaths = JsonToJsonPathsConverter - .transformToJsonPathWithStubsSideValuesAndNoArraySizeCheck(message.getContents().getValue()); - jsonPaths.forEach((j) -> { - responseBodyMatchers.jsonPath(j.keyBeforeChecking(), responseBodyMatchers.byType()); - }); - } - else { - matchingRuleGroup.getRules().forEach((rule) -> { - applyJsonPathToResponseBodyMatchers(rule, matchingRuleKey, responseBodyMatchers); - }); - } - }); - } - - private String getTriggeredBy(Message message) { - String triggeredBy = message.getProviderStates().get(0).getName().replaceAll(":", " ").replaceAll(" ", "_") - .replaceAll("\\(", "").replaceAll("\\)", ""); - return StringUtils.uncapitalize(triggeredBy) + "()"; - } - - private String findDestination(Message message) { - return message.getMetadata().get(DESTINATION_KEY) != null - ? message.getMetadata().get(DESTINATION_KEY).toString() : ""; - } - - void applyJsonPathToResponseBodyMatchers(MatchingRule matchingRule, String key, - ResponseBodyMatchers responseBodyMatchers) { - if (matchingRule instanceof NullMatcher) { - responseBodyMatchers.jsonPath(key, responseBodyMatchers.byNull()); - } - else if (matchingRule instanceof RegexMatcher) { - responseBodyMatchers.jsonPath(key, responseBodyMatchers.byRegex(((RegexMatcher) matchingRule).getRegex())); - } - else if (matchingRule instanceof DateMatcher) { - responseBodyMatchers.jsonPath(key, responseBodyMatchers.byDate()); - } - else if (matchingRule instanceof TimeMatcher) { - responseBodyMatchers.jsonPath(key, responseBodyMatchers.byTime()); - } - else if (matchingRule instanceof TimestampMatcher) { - responseBodyMatchers.jsonPath(key, responseBodyMatchers.byTimestamp()); - } - else if (matchingRule instanceof MinTypeMatcher) { - responseBodyMatchers.jsonPath(key, - responseBodyMatchers.byType((b) -> b.minOccurrence(((MinTypeMatcher) matchingRule).getMin()))); - } - else if (matchingRule instanceof MinMaxTypeMatcher) { - responseBodyMatchers.jsonPath(key, responseBodyMatchers.byType((c) -> { - c.minOccurrence(((MinMaxTypeMatcher) matchingRule).getMin()); - c.maxOccurrence(((MinMaxTypeMatcher) matchingRule).getMax()); - })); - } - else if (matchingRule instanceof MaxTypeMatcher) { - responseBodyMatchers.jsonPath(key, responseBodyMatchers.byType((c) -> { - c.maxOccurrence(((MaxTypeMatcher) matchingRule).getMax()); - })); - } - else if (matchingRule instanceof TypeMatcher) { - responseBodyMatchers.jsonPath(key, responseBodyMatchers.byType()); - } - else if (matchingRule instanceof NumberTypeMatcher) { - switch (((NumberTypeMatcher) matchingRule).getNumberType()) { - case NUMBER: - responseBodyMatchers.jsonPath(key, responseBodyMatchers.byRegex(RegexPatterns.number())); - break; - case INTEGER: - responseBodyMatchers.jsonPath(key, responseBodyMatchers.byRegex(RegexPatterns.anInteger())); - break; - case DECIMAL: - responseBodyMatchers.jsonPath(key, responseBodyMatchers.byRegex(RegexPatterns.aDouble())); - break; - default: - throw new RuntimeException("Unsupported number type!"); - } - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/Names.java b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/Names.java deleted file mode 100644 index c8d67a58e8..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/Names.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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.spec.pact; - -/** - * @author Marcin Grzejszczak - * @author Stessy Delcroix - * @since - */ -class Names { - - private final String consumer; - - private final String producer; - - private final String test; - - Names(String[] strings) { - this.consumer = strings[0]; - this.producer = strings[1]; - this.test = strings.length >= 2 ? strings[2] : ""; - } - - @Override - public String toString() { - return this.consumer + "_" + this.producer; - } - - String getConsumer() { - return consumer; - } - - String getProducer() { - return producer; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/NamingUtil.java b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/NamingUtil.java deleted file mode 100644 index ec61951e65..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/NamingUtil.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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.spec.pact; - -import org.springframework.cloud.contract.spec.Contract; - -/** - * @author Marcin Grzejszczak - * @author Stessy Delcroix - * @since - */ -final class NamingUtil { - - // consumer___producer___testname - private static final String SEPARATOR = "___"; - - private NamingUtil() { - } - - static Names name(Contract contract) { - String contractName = contract.getName(); - if (contractName == null || !contractName.contains(SEPARATOR)) { - return new Names(new String[] { "Consumer", "Provider", "" }); - } - return new Names(contractName.split(SEPARATOR)); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/ObjectMapperFactory.java b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/ObjectMapperFactory.java deleted file mode 100644 index 53a472376e..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/ObjectMapperFactory.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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.spec.pact; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; - -/** - * {@link ObjectMapper} singleton instance creation. - * @author Stessy Delcroix - * @since 2.0.0 - */ -public enum ObjectMapperFactory { - - /** - * Singleton instance constant. - */ - INSTANCE; - - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - - static { - OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_COMMENTS, true); - OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_YAML_COMMENTS, true); - OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); - OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); - OBJECT_MAPPER.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true); - } - - public ObjectMapper getMapper() { - return OBJECT_MAPPER; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverter.java b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverter.java deleted file mode 100644 index 8a266577ae..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverter.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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.spec.pact; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import au.com.dius.pact.core.model.DefaultPactReader; -import au.com.dius.pact.core.model.Pact; -import au.com.dius.pact.core.model.PactSpecVersion; -import au.com.dius.pact.core.model.RequestResponsePact; -import au.com.dius.pact.core.model.messaging.MessagePact; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.util.DefaultIndenter; -import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; -import com.fasterxml.jackson.core.util.Separators; -import com.fasterxml.jackson.databind.ObjectMapper; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.ContractConverter; - -/** - * Converter of JSON PACT file. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @author Stessy Delcroix - * @since 1.1.0 - */ -public class PactContractConverter implements ContractConverter> { - - private static final ObjectMapper OBJECT_MAPPER = ObjectMapperFactory.INSTANCE.getMapper(); - - private final RequestResponseSCContractCreator requestResponseSCContractCreator = new RequestResponseSCContractCreator(); - - private final MessagingSCContractCreator messagingSCContractCreator = new MessagingSCContractCreator(); - - private final RequestResponsePactCreator requestResponsePactCreator = new RequestResponsePactCreator(); - - private final MessagePactCreator messagePactCreator = new MessagePactCreator(); - - @Override - public boolean isAccepted(File file) { - try { - Pact pact = DefaultPactReader.INSTANCE.loadPact(file); - return !pact.getInteractions().isEmpty(); - } - catch (Exception e) { - return false; - } - } - - @Override - public Collection convertFrom(File file) { - Pact pact = DefaultPactReader.INSTANCE.loadPact(file); - if (pact instanceof RequestResponsePact) { - return requestResponseSCContractCreator.convertFrom((RequestResponsePact) pact); - } - if (pact instanceof MessagePact) { - return messagingSCContractCreator.convertFrom((MessagePact) pact); - } - throw new UnsupportedOperationException( - "We currently don't support pact contracts of type" + pact.getClass().getSimpleName()); - } - - @Override - public Collection convertTo(Collection contracts) { - List pactContracts = new ArrayList<>(); - Map> groupedContracts = contracts.stream() - .collect(Collectors.groupingBy(c -> NamingUtil.name(c).toString())); - for (List list : groupedContracts.values()) { - List httpOnly = list.stream().filter(c -> c.getRequest() != null).collect(Collectors.toList()); - List messagingOnly = list.stream().filter(c -> c.getInput() != null).collect(Collectors.toList()); - RequestResponsePact responsePact = requestResponsePactCreator.createFromContract(httpOnly); - if (responsePact != null) { - pactContracts.add(responsePact); - } - MessagePact messagePact = messagePactCreator.createFromContract(messagingOnly); - if (messagePact != null) { - pactContracts.add(messagePact); - } - } - return pactContracts; - } - - @Override - public Map store(Collection contracts) { - return contracts.stream().collect(Collectors.toMap(this::name, c -> { - try { - return this.buildPrettyPrint(OBJECT_MAPPER.writeValueAsString(c.toMap(PactSpecVersion.V3))).getBytes(); - } - catch (JsonProcessingException e) { - throw new IllegalArgumentException("The pact contract is not a valid map", e); - } - })); - } - - protected String name(Pact contract) { - return contract.getConsumer().getName() + "_" + contract.getProvider().getName() + "_" - + Math.abs(contract.hashCode()) + ".json"; - } - - private String buildPrettyPrint(String contract) { - try { - Object intermediateObjectForPrettyPrinting = OBJECT_MAPPER.reader().readValue(contract, Object.class); - DefaultIndenter customIndenter = new DefaultIndenter(" ", "\n"); - return OBJECT_MAPPER - .writer(new CustomPrettyPrinter().withArrayIndenter(customIndenter) - .withObjectIndenter(customIndenter)) - .writeValueAsString(intermediateObjectForPrettyPrinting); - } - catch (IOException e) { - throw new RuntimeException("WireMock response body could not be pretty printed"); - } - } - - private static class CustomPrettyPrinter extends DefaultPrettyPrinter { - - @Override - public CustomPrettyPrinter createInstance() { - return new CustomPrettyPrinter(); - } - - @Override - public DefaultPrettyPrinter withSeparators(Separators separators) { - _separators = separators; - _objectFieldValueSeparatorWithSpaces = separators.getObjectFieldValueSeparator() + " "; - return this; - } - - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/PactMetaData.java b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/PactMetaData.java deleted file mode 100644 index 18da12a9c1..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/PactMetaData.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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.spec.pact; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import au.com.dius.pact.core.model.ProviderState; - -import org.springframework.cloud.contract.verifier.util.MetadataUtil; -import org.springframework.cloud.contract.verifier.util.SpringCloudContractMetadata; -import org.springframework.lang.NonNull; - -public class PactMetaData implements SpringCloudContractMetadata { - - /** - * Key under which this metadata entry can be found in contract's metadata. - */ - public static final String METADATA_KEY = "pact"; - - /** - * Metadata for adding {@link ProviderState} in Pact contract. - */ - private List providerStates = new ArrayList<>(); - - public List getProviderStates() { - return this.providerStates; - } - - public void setProviderStates(List providerStates) { - this.providerStates = providerStates; - } - - @NonNull - public static PactMetaData fromMetadata(Map metadata) { - return MetadataUtil.fromMetadata(metadata, PactMetaData.METADATA_KEY, new PactMetaData()); - } - - @Override - public String key() { - return METADATA_KEY; - } - - @Override - public String description() { - return "Metadata for converting Contract to Pact"; - } - - /** - * {@link ProviderState} metadata. - */ - public static class ProviderStateMetadata { - - /** - * If set, will be added to PACT provider states. - */ - private String name; - - private Map params; - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - public Map getParams() { - return this.params; - } - - public void setParams(Map params) { - this.params = params; - } - - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/RequestResponsePactCreator.java b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/RequestResponsePactCreator.java deleted file mode 100644 index 20c01617b2..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/RequestResponsePactCreator.java +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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.spec.pact; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import au.com.dius.pact.consumer.ConsumerPactBuilder; -import au.com.dius.pact.consumer.dsl.DslPart; -import au.com.dius.pact.consumer.dsl.PactDslRequestWithPath; -import au.com.dius.pact.consumer.dsl.PactDslResponse; -import au.com.dius.pact.consumer.dsl.PactDslWithProvider; -import au.com.dius.pact.consumer.dsl.PactDslWithState; -import au.com.dius.pact.core.model.RequestResponsePact; -import org.apache.commons.lang3.StringUtils; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.internal.Body; -import org.springframework.cloud.contract.spec.internal.Cookies; -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.Header; -import org.springframework.cloud.contract.spec.internal.QueryParameters; -import org.springframework.cloud.contract.spec.internal.RegexProperty; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.spec.internal.Response; -import org.springframework.util.CollectionUtils; - -import static java.util.stream.Collectors.joining; - -/** - * Creator of {@link RequestResponsePact} instances. - * - * @author Tim Ysewyn - * @author Stessy Delcroix - * @since 2.0.0 - */ -class RequestResponsePactCreator { - - RequestResponsePact createFromContract(List contracts) { - if (CollectionUtils.isEmpty(contracts)) { - return null; - } - Names names = NamingUtil.name(contracts.get(0)); - PactDslWithProvider pactDslWithProvider = ConsumerPactBuilder.consumer(names.getConsumer()) - .hasPactWith(names.getProducer()); - PactDslResponse pactDslResponse = null; - for (Contract contract : contracts) { - assertNoExecutionProperty(contract); - PactDslRequestWithPath pactDslRequest = pactDslResponse != null - ? createPactDslRequestWithPath(contract, pactDslResponse) - : createPactDslRequestWithPath(contract, pactDslWithProvider); - pactDslResponse = createPactDslResponse(contract, pactDslRequest); - } - return pactDslResponse.toPact(); - } - - private void assertNoExecutionProperty(Contract contract) { - assertNoExecutionPropertyInBody(contract.getRequest().getBody(), DslProperty::getServerValue); - assertNoExecutionPropertyInBody(contract.getResponse().getBody(), DslProperty::getClientValue); - } - - private void assertNoExecutionPropertyInBody(Body body, - Function, Object> dslPropertyValueExtractor) { - traverseValues(body, dslPropertyValueExtractor, (Object object) -> { - if (object instanceof ExecutionProperty) { - throw new UnsupportedOperationException("We can't convert a contract that has execution property"); - } - return object; - }); - } - - private void traverseValues(Object value, Function, Object> dslPropertyValueExtractor, - Function function) { - if (value instanceof DslProperty) { - traverseValues(dslPropertyValueExtractor.apply((DslProperty) value), dslPropertyValueExtractor, - function); - } - else if (value instanceof Map) { - ((Map) value).values().forEach(v -> traverseValues(v, dslPropertyValueExtractor, function)); - } - else if (value instanceof Collection) { - ((Collection) value).forEach(v -> traverseValues(v, dslPropertyValueExtractor, function)); - } - else { - function.apply(value); - } - } - - private PactDslRequestWithPath createPactDslRequestWithPath(Contract contract, PactDslResponse pactDslResponse) { - PactDslRequestWithPath pactDslRequest = getPactDslRequest(contract, - getPactDslWithStateFunction(pactDslResponse), getPactDslRequestWithPathBiFunction(pactDslResponse)); - Request request = contract.getRequest(); - final PactDslRequestWithPath finalPactDslRequest = pactDslRequest; - if (request.getHeaders() != null) { - request.getHeaders().getEntries().forEach(h -> processHeader(finalPactDslRequest, h)); - } - if (request.getCookies() != null) { - pactDslRequest = processCookies(finalPactDslRequest, request.getCookies()); - } - if (request.getBody() != null) { - DslPart pactRequestBody = BodyConverter.toPactBody(request.getBody(), DslProperty::getClientValue); - if (request.getBodyMatchers() != null) { - pactRequestBody.setMatchers(MatchingRulesConverter.matchingRulesForBody(request.getBodyMatchers())); - } - pactRequestBody - .setGenerators(ValueGeneratorConverter.extract(request.getBody(), DslProperty::getClientValue)); - pactDslRequest = pactDslRequest.body(pactRequestBody); - } - return pactDslRequest; - } - - private Function getPactDslWithStateFunction( - PactDslResponse pactDslResponse) { - return stateMetadata -> pactDslResponse.given(stateMetadata.getName(), stateMetadata.getParams()); - } - - private BiFunction getPactDslRequestWithPathBiFunction( - PactDslResponse pactDslResponse) { - return (description, request) -> pactDslResponse.uponReceiving(description).path(url(request)) - .method(request.getMethod().getServerValue().toString()); - } - - private PactDslRequestWithPath createPactDslRequestWithPath(Contract contract, - PactDslWithProvider pactDslWithProvider) { - PactDslRequestWithPath pactDslRequest = getPactDslRequest(contract, - getPactDslWithStateFunction(pactDslWithProvider), - getPactDslRequestWithPathBiFunction(pactDslWithProvider)); - Request request = contract.getRequest(); - final PactDslRequestWithPath finalPactDslRequest = pactDslRequest; - if (request.getHeaders() != null) { - request.getHeaders().getEntries().forEach(h -> processHeader(finalPactDslRequest, h)); - } - if (request.getBody() != null) { - DslPart pactRequestBody = BodyConverter.toPactBody(request.getBody(), DslProperty::getServerValue); - if (request.getBodyMatchers() != null) { - pactRequestBody.setMatchers(MatchingRulesConverter.matchingRulesForBody(request.getBodyMatchers())); - } - pactRequestBody - .setGenerators(ValueGeneratorConverter.extract(request.getBody(), DslProperty::getClientValue)); - pactDslRequest = pactDslRequest.body(pactRequestBody); - } - return pactDslRequest; - } - - private Function getPactDslWithStateFunction( - PactDslWithProvider pactDslWithProvider) { - return stateMetadata -> pactDslWithProvider.given(stateMetadata.getName(), stateMetadata.getParams()); - } - - private BiFunction getPactDslRequestWithPathBiFunction( - PactDslWithProvider pactDslWithProvider) { - return (description, request) -> pactDslWithProvider.uponReceiving(description).path(url(request)) - .method(request.getMethod().getServerValue().toString()); - } - - private PactDslRequestWithPath getPactDslRequest(Contract contract, - Function pactDslWithStateFunction, - BiFunction pactDslRequestWithPathBiFunction) { - PactDslWithState pactDslWithState = getPactDslWithState(contract, pactDslWithStateFunction); - String description = StringUtils.isNotBlank(contract.getDescription()) ? contract.getDescription() : ""; - Request request = contract.getRequest(); - PactDslRequestWithPath pactDslRequest; - if (pactDslWithState != null) { - pactDslRequest = pactDslWithState.uponReceiving(description).path(url(request)) - .method(request.getMethod().getServerValue().toString()); - } - else { - pactDslRequest = pactDslRequestWithPathBiFunction.apply(description, request); - } - String query = query(request); - if (StringUtils.isNotBlank(query)) { - pactDslRequest = pactDslRequest.encodedQuery(query); - } - return pactDslRequest; - } - - private PactDslWithState getPactDslWithState(Contract contract, - Function pactDslWithStateFunction) { - PactDslWithState pactDslWithState = null; - if (contract.getMetadata().containsKey(PactMetaData.METADATA_KEY)) { - PactMetaData metadata = PactMetaData.fromMetadata(contract.getMetadata()); - if (!metadata.getProviderStates().isEmpty()) { - for (PactMetaData.ProviderStateMetadata stateMetadata : metadata.getProviderStates()) { - if (pactDslWithState == null) { - pactDslWithState = pactDslWithStateFunction.apply(stateMetadata); - } - else { - pactDslWithState = pactDslWithState.given(stateMetadata.getName(), stateMetadata.getParams()); - } - } - } - } - return pactDslWithState; - } - - private String url(Request request) { - if (request.getUrlPath() != null) { - return request.getUrlPath().getServerValue().toString(); - } - else if (request.getUrl() != null) { - return request.getUrl().getServerValue().toString(); - } - throw new IllegalStateException("No url provided"); - } - - private String query(Request request) { - final StringBuilder query = new StringBuilder(); - QueryParameters params = queryParams(request); - if (params != null) { - AtomicInteger index = new AtomicInteger(); - params.getParameters().forEach(p -> { - query.append(p.getName()).append('=').append(p.getServerValue()); - if (index.incrementAndGet() < params.getParameters().size()) { - query.append('&'); - } - - }); - } - return query.toString(); - } - - private QueryParameters queryParams(Request request) { - if (request.getUrlPath() != null) { - return request.getUrlPath().getQueryParameters(); - } - else if (request.getUrl() != null) { - return request.getUrl().getQueryParameters(); - } - throw new IllegalStateException("No url provided"); - - } - - private PactDslRequestWithPath processHeader(PactDslRequestWithPath pactDslRequest, Header header) { - if (header.isSingleValue()) { - String value = getDslPropertyServerValue(header).toString(); - return pactDslRequest.headers(header.getName(), value); - } - else { - String regex = getDslPropertyClientValue(header).toString(); - String example = getDslPropertyServerValue(header).toString(); - return pactDslRequest.matchHeader(header.getName(), regex, example); - } - } - - private String stubSideCookieExample(Cookies cookies) { - return cookies.asStubSideMap().entrySet().stream().map(Object::toString).collect(joining(";")); - } - - private Object getDslPropertyClientValue(Object o) { - Object value = o; - if (value instanceof DslProperty) { - value = getDslPropertyClientValue(((DslProperty) value).getClientValue()); - } - return value; - } - - private Object getDslPropertyServerValue(Object o) { - Object value = o; - if (value instanceof DslProperty) { - value = getDslPropertyServerValue(((DslProperty) value).getServerValue()); - } - return value; - } - - private PactDslRequestWithPath processCookies(PactDslRequestWithPath pactDslRequest, Cookies cookies) { - Map stubSideCookies = cookies.asStubSideMap(); - Collection regexProperties = stubSideCookies.values().stream() - .filter(r -> r instanceof Pattern || r instanceof RegexProperty).map(RegexProperty::new) - .collect(Collectors.toList()); - if (!regexProperties.isEmpty()) { - String regex = regexProperties.stream().map(RegexProperty::pattern).collect(joining("|")); - return pactDslRequest.matchHeader("Cookie", regex, testSideCookieExample(cookies)); - } - else { - return pactDslRequest.headers("Cookie", testSideCookieExample(cookies)); - } - } - - private String testSideCookieExample(Cookies cookies) { - return cookies.asTestSideMap().entrySet().stream().map(Object::toString).collect(joining(";")); - } - - private PactDslResponse createPactDslResponse(Contract contract, PactDslRequestWithPath pactDslRequest) { - Response response = contract.getResponse(); - PactDslResponse pactDslResponse = pactDslRequest.willRespondWith() - .status((Integer) response.getStatus().getClientValue()); - - PactDslResponse finalPactDslResponse = pactDslResponse; - if (response.getHeaders() != null) { - response.getHeaders().getEntries().forEach(h -> processHeader(finalPactDslResponse, h)); - } - - if (response.getCookies() != null) { - pactDslResponse = processCookies(pactDslResponse, response.getCookies()); - } - if (response.getBody() != null) { - DslPart pactResponseBody = BodyConverter.toPactBody(response.getBody(), DslProperty::getClientValue); - if (response.getBodyMatchers() != null) { - pactResponseBody.setMatchers(MatchingRulesConverter.matchingRulesForBody(response.getBodyMatchers())); - } - pactResponseBody - .setGenerators(ValueGeneratorConverter.extract(response.getBody(), DslProperty::getServerValue)); - pactDslResponse = pactDslResponse.body(pactResponseBody); - } - return pactDslResponse; - } - - private PactDslResponse processHeader(PactDslResponse pactDslResponse, Header header) { - if (header.isSingleValue()) { - String value = getDslPropertyClientValue(header).toString(); - return pactDslResponse.headers(Collections.singletonMap(header.getName(), value)); - } - else { - String regex = getDslPropertyServerValue(header).toString(); - String example = getDslPropertyClientValue(header).toString(); - return pactDslResponse.matchHeader(header.getName(), regex, example); - } - } - - private PactDslResponse processCookies(PactDslResponse pactDslResponse, Cookies cookies) { - Map testSideCookies = cookies.asTestSideMap(); - Collection regexProperties = testSideCookies.values().stream() - .filter(p -> p instanceof Pattern || p instanceof RegexProperty).map(RegexProperty::new) - .collect(Collectors.toList()); - if (!regexProperties.isEmpty()) { - String regex = regexProperties.stream().map(RegexProperty::pattern).collect(joining("|")); - return pactDslResponse.matchHeader("Cookie", regex, stubSideCookieExample(cookies)); - } - else { - return pactDslResponse.headers(Collections.singletonMap("Cookie", stubSideCookieExample(cookies))); - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/RequestResponseSCContractCreator.java b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/RequestResponseSCContractCreator.java deleted file mode 100644 index b6bb93f7fe..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/RequestResponseSCContractCreator.java +++ /dev/null @@ -1,432 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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.spec.pact; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import au.com.dius.pact.core.model.Interaction; -import au.com.dius.pact.core.model.OptionalBody; -import au.com.dius.pact.core.model.ProviderState; -import au.com.dius.pact.core.model.Request; -import au.com.dius.pact.core.model.RequestResponseInteraction; -import au.com.dius.pact.core.model.RequestResponsePact; -import au.com.dius.pact.core.model.Response; -import au.com.dius.pact.core.model.matchingrules.DateMatcher; -import au.com.dius.pact.core.model.matchingrules.MatchingRule; -import au.com.dius.pact.core.model.matchingrules.MatchingRuleCategory; -import au.com.dius.pact.core.model.matchingrules.MatchingRuleGroup; -import au.com.dius.pact.core.model.matchingrules.MaxTypeMatcher; -import au.com.dius.pact.core.model.matchingrules.MinMaxTypeMatcher; -import au.com.dius.pact.core.model.matchingrules.MinTypeMatcher; -import au.com.dius.pact.core.model.matchingrules.NullMatcher; -import au.com.dius.pact.core.model.matchingrules.NumberTypeMatcher; -import au.com.dius.pact.core.model.matchingrules.RegexMatcher; -import au.com.dius.pact.core.model.matchingrules.RuleLogic; -import au.com.dius.pact.core.model.matchingrules.TimeMatcher; -import au.com.dius.pact.core.model.matchingrules.TimestampMatcher; -import au.com.dius.pact.core.model.matchingrules.TypeMatcher; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.internal.RegexPatterns; -import org.springframework.cloud.contract.verifier.util.JsonPaths; -import org.springframework.cloud.contract.verifier.util.JsonToJsonPathsConverter; - -/** - * Creator of {@link Contract} instances. - * - * @author Tim Ysewyn - * @author Stessy Delcroix - * @since 2.0.0 - */ -class RequestResponseSCContractCreator { - - private static final String FULL_BODY = "$"; - - Collection convertFrom(RequestResponsePact pact) { - return pact.getInteractions().stream().map(interaction -> Contract.make(contract -> { - mapContractDescription(interaction, contract); - mapContractRequest(interaction, contract); - mapContractResponse(interaction, contract); - })).collect(Collectors.toList()); - } - - private void mapContractDescription(Interaction interaction, Contract contract) { - contract.description(buildDescription(interaction)); - } - - private void mapContractRequest(Interaction inter, Contract contract) { - contract.request((contractRequest) -> { - if (!(inter instanceof RequestResponseInteraction)) { - return; - } - RequestResponseInteraction interaction = (RequestResponseInteraction) inter; - Request pactRequest = interaction.getRequest(); - contractRequest.method(pactRequest.getMethod()); - mapRequestUrl(contractRequest, pactRequest); - - if (!pactRequest.getHeaders().isEmpty()) { - mapRequestHeaders(contractRequest, pactRequest); - } - if (pactRequest.getHeaders().containsKey("Cookie")) { - mapRequestCookies(contractRequest, pactRequest); - } - if (pactRequest.getBody().getState() == OptionalBody.State.PRESENT) { - mapRequestBody(contractRequest, pactRequest); - } - MatchingRuleCategory bodyRules = pactRequest.getMatchingRules().rulesForCategory("body"); - if (!bodyRules.getMatchingRules().isEmpty()) { - mapRequestBodyRules(contractRequest, bodyRules); - } - }); - } - - private void mapContractResponse(Interaction inter, Contract contract) { - contract.response((contractResponse) -> { - if (!(inter instanceof RequestResponseInteraction)) { - return; - } - RequestResponseInteraction interaction = (RequestResponseInteraction) inter; - Response pactResponse = interaction.getResponse(); - contractResponse.status(pactResponse.getStatus()); - if (pactResponse.getBody().isPresent()) { - mapResponseBody(contractResponse, pactResponse); - } - - MatchingRuleCategory bodyRules = pactResponse.getMatchingRules().rulesForCategory("body"); - if (!bodyRules.getMatchingRules().isEmpty()) { - mapResponseBodyRules(contractResponse, pactResponse, bodyRules); - } - if (!pactResponse.getHeaders().isEmpty()) { - mapResponseHeaders(contractResponse, pactResponse); - } - - if (pactResponse.getHeaders().containsKey("Cookie")) { - mapResponseCookies(contractResponse, pactResponse); - } - }); - } - - private void mapResponseBodyRules(org.springframework.cloud.contract.spec.internal.Response contractResponse, - Response pactResponse, MatchingRuleCategory bodyRules) { - contractResponse.bodyMatchers((bodyMatchers) -> { - bodyRules.getMatchingRules().forEach((key, matchindRuleGroup) -> { - if (matchindRuleGroup.getRuleLogic() != RuleLogic.AND) { - throw new UnsupportedOperationException( - "Currently only the AND combination rule logic is supported"); - } - if (FULL_BODY.equals(key)) { - JsonPaths jsonPaths = JsonToJsonPathsConverter - .transformToJsonPathWithStubsSideValuesAndNoArraySizeCheck( - new String(pactResponse.getBody().getValue())); - jsonPaths.forEach( - (jsonPath) -> bodyMatchers.jsonPath(jsonPath.keyBeforeChecking(), bodyMatchers.byType())); - } - else { - matchindRuleGroup.getRules().forEach((matchingRule) -> { - if (matchingRule instanceof NullMatcher) { - bodyMatchers.jsonPath(key, bodyMatchers.byNull()); - } - else if (matchingRule instanceof RegexMatcher) { - bodyMatchers.jsonPath(key, bodyMatchers.byRegex(((RegexMatcher) matchingRule).getRegex())); - } - else if (matchingRule instanceof DateMatcher) { - bodyMatchers.jsonPath(key, bodyMatchers.byDate()); - } - else if (matchingRule instanceof TimeMatcher) { - bodyMatchers.jsonPath(key, bodyMatchers.byTime()); - } - else if (matchingRule instanceof TimestampMatcher) { - bodyMatchers.jsonPath(key, bodyMatchers.byTimestamp()); - } - else if (matchingRule instanceof MinTypeMatcher) { - bodyMatchers.jsonPath(key, bodyMatchers.byType((valueHolder) -> valueHolder - .minOccurrence((((MinTypeMatcher) matchingRule).getMin())))); - } - else if (matchingRule instanceof MinMaxTypeMatcher) { - bodyMatchers.jsonPath(key, bodyMatchers.byType((valueHolder) -> { - valueHolder.minOccurrence((((MinMaxTypeMatcher) matchingRule).getMin())); - valueHolder.maxOccurrence((((MinMaxTypeMatcher) matchingRule).getMax())); - })); - } - else if (matchingRule instanceof MaxTypeMatcher) { - bodyMatchers.jsonPath(key, bodyMatchers.byType((valueHolder) -> valueHolder - .maxOccurrence((((MaxTypeMatcher) matchingRule).getMax())))); - } - else if (matchingRule instanceof TypeMatcher) { - bodyMatchers.jsonPath(key, bodyMatchers.byType()); - } - else if (matchingRule instanceof NumberTypeMatcher) { - switch (((NumberTypeMatcher) matchingRule).getNumberType()) { - case NUMBER: - bodyMatchers.jsonPath(key, bodyMatchers.byRegex(RegexPatterns.number())); - break; - case INTEGER: - bodyMatchers.jsonPath(key, bodyMatchers.byRegex(RegexPatterns.anInteger())); - break; - case DECIMAL: - bodyMatchers.jsonPath(key, bodyMatchers.byRegex(RegexPatterns.aDouble())); - break; - default: - throw new UnsupportedOperationException("Unsupported number type!"); - } - } - }); - } - }); - }); - } - - private void mapResponseBody(org.springframework.cloud.contract.spec.internal.Response contractResponse, - Response pactResponse) { - Object parsedBody = BodyConverter.toSCCBody(pactResponse); - if (parsedBody instanceof Map) { - contractResponse.body((Map) parsedBody); - } - else if (parsedBody instanceof List) { - contractResponse.body((List) parsedBody); - } - else { - contractResponse.body(parsedBody.toString()); - } - } - - private void mapRequestBodyRules(org.springframework.cloud.contract.spec.internal.Request contractRequest, - MatchingRuleCategory bodyRules) { - contractRequest.bodyMatchers((bodyMatchers) -> { - bodyRules.getMatchingRules().forEach((key, matchingRuleGroup) -> { - if (matchingRuleGroup.getRuleLogic() != RuleLogic.AND) { - throw new UnsupportedOperationException( - "Currently only the AND combination rule logic is supported"); - } - - matchingRuleGroup.getRules().forEach((matchingRule) -> { - if (matchingRule instanceof RegexMatcher) { - bodyMatchers.jsonPath(key, bodyMatchers.byRegex(((RegexMatcher) matchingRule).getRegex())); - } - else if (matchingRule instanceof DateMatcher) { - bodyMatchers.jsonPath(key, bodyMatchers.byDate()); - } - else if (matchingRule instanceof TimeMatcher) { - bodyMatchers.jsonPath(key, bodyMatchers.byTime()); - } - else if (matchingRule instanceof TimestampMatcher) { - bodyMatchers.jsonPath(key, bodyMatchers.byTimestamp()); - } - else if (matchingRule instanceof NumberTypeMatcher) { - switch (((NumberTypeMatcher) matchingRule).getNumberType()) { - case NUMBER: - bodyMatchers.jsonPath(key, bodyMatchers.byRegex(RegexPatterns.number())); - break; - case INTEGER: - bodyMatchers.jsonPath(key, bodyMatchers.byRegex(RegexPatterns.anInteger())); - break; - case DECIMAL: - bodyMatchers.jsonPath(key, bodyMatchers.byRegex(RegexPatterns.aDouble())); - break; - default: - throw new RuntimeException("Unsupported number type!"); - } - } - }); - }); - }); - } - - private void mapRequestBody(org.springframework.cloud.contract.spec.internal.Request contractRequest, - Request pactRequest) { - Object parsedBody = BodyConverter.toSCCBody(pactRequest); - if (parsedBody instanceof Map) { - contractRequest.body((Map) parsedBody); - } - else if (parsedBody instanceof List) { - contractRequest.body((List) parsedBody); - } - else { - contractRequest.body(parsedBody.toString()); - } - } - - private void mapRequestCookies(org.springframework.cloud.contract.spec.internal.Request contractRequest, - Request pactRequest) { - MatchingRuleCategory headerRules = pactRequest.getMatchingRules().rulesForCategory("header"); - String[] splitCookiesHeader = pactRequest.getHeaders().get("Cookie").get(0).split(";"); - Map foundCookies = Stream.of(splitCookiesHeader).map((cookieHeader) -> cookieHeader.split("=")) - .collect(Collectors.toMap(splittedCookieHeader -> splittedCookieHeader[0], - splittedCookieHeader -> splittedCookieHeader[1])); - - contractRequest.cookies((cookies) -> foundCookies.forEach((key, value) -> { - if (headerRules.getMatchingRules().containsKey("Cookie")) { - MatchingRuleGroup matchingRuleGroup = headerRules.getMatchingRules().get("Cookie"); - if (matchingRuleGroup.getRules().size() > 1) { - throw new UnsupportedOperationException( - "Currently only 1 rule at a time for a header is supported"); - } - MatchingRule matchingRule = matchingRuleGroup.getRules().get(0); - if (matchingRule instanceof RegexMatcher) { - cookies.cookie(key, - contractRequest.$( - contractRequest.c(contractRequest.regex(((RegexMatcher) matchingRule).getRegex())), - contractRequest.p(value))); - } - else { - throw new UnsupportedOperationException( - "Currently only the header matcher of type regex is supported"); - } - } - else { - cookies.cookie(key, value); - } - })); - } - - private void mapResponseCookies(org.springframework.cloud.contract.spec.internal.Response contractResponse, - Response pactResponse) { - MatchingRuleCategory headerRules = pactResponse.getMatchingRules().rulesForCategory("header"); - String[] splitCookiesHeader = pactResponse.getHeaders().get("Cookie").get(0).split(";"); - Map foundCookies = Stream.of(splitCookiesHeader).map((cookieHeader) -> cookieHeader.split("=")) - .collect(Collectors.toMap(splittedCookieHeader -> splittedCookieHeader[0], - splittedCookieHeader -> splittedCookieHeader[1])); - - contractResponse.cookies((cookies) -> foundCookies.forEach((key, value) -> { - if (headerRules.getMatchingRules().containsKey("Cookie")) { - MatchingRuleGroup matchingRuleGroup = headerRules.getMatchingRules().get("Cookie"); - if (matchingRuleGroup.getRules().size() > 1) { - throw new UnsupportedOperationException( - "Currently only 1 rule at a time for a header is supported"); - } - MatchingRule matchingRule = matchingRuleGroup.getRules().get(0); - if (matchingRule instanceof RegexMatcher) { - cookies.cookie(key, contractResponse.$( - contractResponse.p( - contractResponse.regex(Pattern.compile(((RegexMatcher) matchingRule).getRegex()))), - contractResponse.c(value))); - } - else { - throw new UnsupportedOperationException( - "Currently only the header matcher of type regex is supported"); - } - } - else { - cookies.cookie(key, value); - } - })); - } - - private void mapRequestUrl(org.springframework.cloud.contract.spec.internal.Request contractRequest, - Request pactRequest) { - if (!pactRequest.getQuery().isEmpty()) { - contractRequest.url(pactRequest.getPath(), - (url) -> url.queryParameters((queryParameters) -> pactRequest.getQuery().forEach((key, - values) -> values.forEach((singleValue) -> queryParameters.parameter(key, singleValue))))); - } - else { - contractRequest.url(pactRequest.getPath()); - } - } - - private void mapRequestHeaders(org.springframework.cloud.contract.spec.internal.Request contractRequest, - Request pactRequest) { - MatchingRuleCategory headerRules = pactRequest.getMatchingRules().rulesForCategory("header"); - contractRequest.headers((headers) -> pactRequest.getHeaders().forEach((key, values) -> { - if (key.equalsIgnoreCase("Cookie")) { - return; - } - if (headerRules.getMatchingRules().containsKey(key)) { - MatchingRuleGroup matchingRuleGroup = headerRules.getMatchingRules().get(key); - if (matchingRuleGroup.getRules().size() > 1) { - throw new UnsupportedOperationException( - "Currently only 1 rule at a time for a header is supported"); - } - MatchingRule matchingRule = matchingRuleGroup.getRules().get(0); - if (matchingRule instanceof RegexMatcher) { - values.forEach((value) -> { - headers.header(key, - contractRequest.$( - contractRequest - .c(contractRequest.regex(((RegexMatcher) matchingRule).getRegex())), - contractRequest.p(value))); - }); - } - else { - throw new UnsupportedOperationException( - "Currently only the header matcher of type regex is supported"); - } - } - else { - values.forEach((value) -> headers.header(key, value)); - } - })); - } - - private void mapResponseHeaders(org.springframework.cloud.contract.spec.internal.Response contractResponse, - Response pactResponse) { - MatchingRuleCategory headerRules = pactResponse.getMatchingRules().rulesForCategory("header"); - contractResponse.headers((headers) -> pactResponse.getHeaders().forEach((key, values) -> { - if (key.equalsIgnoreCase("Cookie")) { - return; - } - if (headerRules.getMatchingRules().containsKey(key)) { - MatchingRuleGroup matchingRuleGroup = headerRules.getMatchingRules().get(key); - if (matchingRuleGroup.getRules().size() > 1) { - throw new UnsupportedOperationException( - "Currently only 1 rule at a time for a header is supported"); - } - MatchingRule matchingRule = matchingRuleGroup.getRules().get(0); - if (matchingRule instanceof RegexMatcher) { - values.forEach((value) -> { - headers.header(key, - contractResponse.$( - contractResponse.p(contractResponse - .regex(Pattern.compile(((RegexMatcher) matchingRule).getRegex()))), - contractResponse.c(value))); - }); - } - else { - throw new UnsupportedOperationException( - "Currently only the header matcher of type regex is supported"); - } - } - else { - values.forEach((value) -> headers.header(key, value)); - } - })); - } - - private String buildDescription(Interaction interaction) { - StringBuilder description = new StringBuilder(interaction.getDescription()); - List providerStates = interaction.getProviderStates(); - for (ProviderState providerState : providerStates) { - description.append(" ").append(providerState.getName()); - Map params = providerState.getParams(); - if (!params.isEmpty()) { - description.append("("); - params.forEach((k, v) -> { - description.append(k).append(": ").append(v.toString()).append(", "); - }); - description.delete(description.length() - 2, description.length()); - description.append(")"); - } - } - return description.toString(); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/ValueGeneratorConverter.java b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/ValueGeneratorConverter.java deleted file mode 100644 index 273a3ae4de..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/java/org/springframework/cloud/contract/verifier/spec/pact/ValueGeneratorConverter.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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.spec.pact; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.regex.Pattern; - -import au.com.dius.pact.core.model.generators.Category; -import au.com.dius.pact.core.model.generators.DateGenerator; -import au.com.dius.pact.core.model.generators.DateTimeGenerator; -import au.com.dius.pact.core.model.generators.Generator; -import au.com.dius.pact.core.model.generators.Generators; -import au.com.dius.pact.core.model.generators.RandomBooleanGenerator; -import au.com.dius.pact.core.model.generators.RandomDecimalGenerator; -import au.com.dius.pact.core.model.generators.RandomHexadecimalGenerator; -import au.com.dius.pact.core.model.generators.RandomIntGenerator; -import au.com.dius.pact.core.model.generators.RandomStringGenerator; -import au.com.dius.pact.core.model.generators.RegexGenerator; -import au.com.dius.pact.core.model.generators.TimeGenerator; -import au.com.dius.pact.core.model.generators.UuidGenerator; -import groovy.lang.GString; -import org.apache.commons.lang3.StringUtils; - -import org.springframework.cloud.contract.spec.internal.Body; -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.OutputMessage; -import org.springframework.cloud.contract.spec.internal.RegexProperty; -import org.springframework.cloud.contract.verifier.util.ContentUtils; - -/** - * Convert a value for a given {@link Generator}. - * - * @author Tim Ysewyn - * @author Stessy Delcroix - * @since 2.0.0 - */ -final class ValueGeneratorConverter { - - private static final String INTEGER_PATTERN = "-?(\\d+)"; - - private static final Pattern INTEGER = Pattern.compile(INTEGER_PATTERN); - - private static final String DECIMAL_PATTERN = "-?(\\d*\\.\\d+)"; - - private static final Pattern DECIMAL = Pattern.compile(DECIMAL_PATTERN); - - private static final String HEX_PATTERN = "[a-fA-F0-9]+"; - - private static final Pattern HEX = Pattern.compile(HEX_PATTERN); - - private static final String ALPHA_NUMERIC_PATTERN = "[a-zA-Z0-9]+"; - - private static final Pattern ALPHA_NUMERIC = Pattern.compile(ALPHA_NUMERIC_PATTERN); - - private static final String UUID_PATTERN = "[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"; - - private static final Pattern UUID = Pattern.compile(UUID_PATTERN); - - private static final String ANY_DATE_PATTERN = "(\\d\\d\\d\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])"; - - private static final Pattern ANY_DATE = Pattern.compile(ANY_DATE_PATTERN); - - private static final String ANY_TIME_PATTERN = "(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])"; - - private static final Pattern ANY_TIME = Pattern.compile(ANY_TIME_PATTERN); - - private static final String ANY_DATE_TIME_PATTERN = "([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])"; - - private static final Pattern ANY_DATE_TIME = Pattern.compile(ANY_DATE_TIME_PATTERN); - - private static final String TRUE_OR_FALSE_PATTERN = "(true|false)"; - - private static final Pattern TRUE_OR_FALSE = Pattern.compile(TRUE_OR_FALSE_PATTERN); - - private ValueGeneratorConverter() { - - } - - static DslProperty convert(Generator generator, - BiFunction> dslPropertyProvider) { - Pattern pattern = null; - if (generator instanceof RandomIntGenerator) { - pattern = INTEGER; - } - else if (generator instanceof RandomDecimalGenerator) { - pattern = DECIMAL; - } - else if (generator instanceof RandomHexadecimalGenerator) { - pattern = HEX; - } - else if (generator instanceof RandomStringGenerator) { - pattern = ALPHA_NUMERIC; - } - else if (generator instanceof RegexGenerator) { - pattern = Pattern.compile(((RegexGenerator) generator).getRegex()); - } - else if (generator instanceof UuidGenerator) { - pattern = UUID; - } - else if (generator instanceof DateGenerator) { - pattern = getDateTimePattern(((DateGenerator) generator).getFormat(), ANY_DATE); - } - else if (generator instanceof TimeGenerator) { - pattern = getDateTimePattern(((TimeGenerator) generator).getFormat(), ANY_TIME); - } - else if (generator instanceof DateTimeGenerator) { - pattern = getDateTimePattern(((DateTimeGenerator) generator).getFormat(), ANY_DATE_TIME); - } - else if (generator instanceof RandomBooleanGenerator) { - pattern = TRUE_OR_FALSE; - } - if (pattern == null) { - throw new UnsupportedOperationException( - "We currently don't support a generator of type " + generator.getClass().getSimpleName()); - } - else { - Object generatedValue = generator.generate(new HashMap<>(), null); - return dslPropertyProvider.apply(pattern, generatedValue); - } - } - - private static Pattern getDateTimePattern(String format, Pattern defaultPattern) { - return StringUtils.isNotBlank(format) ? Pattern.compile(format) : defaultPattern; - } - - static Generators extract(Body body, Function, Object> dslPropertyValueProvider) { - Generators generators = new Generators(); - traverse(body, dslPropertyValueProvider, "", generators, Category.BODY); - return generators; - } - - static Generators extract(OutputMessage message, Function, Object> dslPropertyValueProvider) { - Generators generators = new Generators(); - traverse(message.getBody(), dslPropertyValueProvider, "", generators, Category.BODY); - return generators; - } - - private static void traverse(Object value, Function, Object> dslPropertyValueProvider, String path, - Generators generators, Category category) { - Object v = value; - if (v instanceof DslProperty) { - v = dslPropertyValueProvider.apply((DslProperty) v); - } - if (v instanceof GString) { - v = ContentUtils.extractValue((GString) v, dslPropertyValueProvider); - } - if (v instanceof Map) { - ((Map) v).forEach( - (key, val) -> traverse(val, dslPropertyValueProvider, path + "." + key, generators, category)); - } - else if (v instanceof Collection) { - AtomicInteger index = new AtomicInteger(); - ((Collection) v).forEach(val -> traverse(val, dslPropertyValueProvider, - path + "[" + index.getAndIncrement() + "]", generators, category)); - } - else if (v instanceof DslProperty) { - traverse(v, dslPropertyValueProvider, path, generators, category); - } - else if (v instanceof RegexProperty || v instanceof Pattern) { - RegexProperty regexProperty = new RegexProperty(v); - switch (regexProperty.pattern()) { - case INTEGER_PATTERN: - generators.addGenerator(category, path, new RandomIntGenerator(0, Integer.MAX_VALUE)); - break; - case DECIMAL_PATTERN: - generators.addGenerator(category, path, new RandomDecimalGenerator(10)); - break; - case HEX_PATTERN: - generators.addGenerator(category, path, new RandomHexadecimalGenerator(10)); - break; - case ALPHA_NUMERIC_PATTERN: - generators.addGenerator(category, path, new RandomStringGenerator(10)); - break; - case UUID_PATTERN: - generators.addGenerator(category, path, new UuidGenerator()); - break; - case ANY_DATE_PATTERN: - generators.addGenerator(category, path, new DateGenerator()); - break; - case ANY_TIME_PATTERN: - generators.addGenerator(category, path, new TimeGenerator()); - break; - case ANY_DATE_TIME_PATTERN: - generators.addGenerator(category, path, new DateTimeGenerator()); - break; - case TRUE_OR_FALSE_PATTERN: - generators.addGenerator(category, path, RandomBooleanGenerator.INSTANCE); - break; - default: - generators.addGenerator(category, path, new RegexGenerator(regexProperty.pattern())); - break; - } - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/resources/META-INF/spring.factories b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/resources/META-INF/spring.factories deleted file mode 100644 index e502013912..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,4 +0,0 @@ -org.springframework.cloud.contract.spec.ContractConverter=\ -org.springframework.cloud.contract.verifier.spec.pact.PactContractConverter -org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder=\ -org.springframework.cloud.contract.stubrunner.PactStubDownloaderBuilder diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/groovy/org/springframework/cloud/contract/stubrunner/PactStubDownloaderBuilderSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/groovy/org/springframework/cloud/contract/stubrunner/PactStubDownloaderBuilderSpec.groovy deleted file mode 100644 index 4ba7756350..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/groovy/org/springframework/cloud/contract/stubrunner/PactStubDownloaderBuilderSpec.groovy +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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.stubrunner - -import java.nio.file.Files - -import au.com.dius.pact.core.model.Pact -import au.com.dius.pact.core.model.PactSource -import au.com.dius.pact.provider.junitsupport.loader.PactLoader -import au.com.dius.pact.core.support.expressions.ValueResolver -import com.github.tomakehurst.wiremock.stubbing.StubMapping -import spock.lang.Ignore -import spock.lang.Specification - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.spec.pact.PactContractConverter - -/** - * @author Marcin Grzejszczak - * @author Tim Ysewyn - */ -@Ignore("Flakey") -class PactStubDownloaderBuilderSpec extends Specification { - - def "should retrieve pacts from broker"() throws IOException { - given: - Collection pacts = new PactContractConverter(). - convertTo([Contract.make { - request { - url "/foo" - method GET() - } - response { - status OK() - } - }, Contract.make { - request { - url "/bar" - method GET() - } - response { - status OK() - } - }]) - StubRunnerOptions options = new StubRunnerOptionsBuilder() - .withProperties(props()) - .build() - PactStubDownloader downloader = new PactStubDownloader(options) { - @Override - PactLoader pactBrokerLoader(ValueResolver resolver, - List tags) { - return new PactLoader() { - @Override - List load(String providerName) { - return pacts - } - - @Override - PactSource getPactSource() { - return null - } - } - } - } - when: - Map.Entry entry = downloader - . - downloadAndUnpackStubJar(new StubConfiguration("com.example:bobby:+:classifier")) - then: - entry != null - entry.getValue().exists() - File contracts = new File(entry.getValue(), "com/example/bobby/contracts") - contracts.exists() - contracts.list() != null - File mappings = new File(entry.getValue(), "com/example/bobby/mappings") - mappings.exists() - mappings.list() != null - mappings.list().size() == 2 - StubMapping.buildFrom(new String(Files. - readAllBytes(mappings.listFiles()[0].toPath()))) - StubMapping.buildFrom(new String(Files. - readAllBytes(mappings.listFiles()[1].toPath()))) - } - - Map props() { - Map map = new HashMap<>() -// map.put("pactbroker.host", "localhost") -// map.put("pactbroker.port", String.valueOf(this.port)) -// map.put("pactbroker.host", "test.pact.dius.com.au") -// map.put("pactbroker.port", "443") -// map.put("pactbroker.protocol", "https") -// map.put("pactbroker.auth.scheme", "Basic") -// map.put("pactbroker.auth.username", "dXfltyFMgNOFZAxr8io9wJ37iUpY42M") -// map.put("pactbroker.auth.password", "O5AIZWxelWbLvqMd8PkAVycBJh2Psyg1") - return map - } - - // @After - // void tearDown() { - // SnapshotRecordResult recording = WireMock.stopRecording() - // List mappings = recording.getStubMappings() - // storeMappings(mappings) - // } - -// private void recordFromBroker() { -// WireMock.startRecording(WireMock.recordSpec() -// .forTarget("https://test.pact.dius.com.au") -// .extractTextBodiesOver(9999999L) -// .extractBinaryBodiesOver(9999999L) -// .makeStubsPersistent(false)) -// } - - // private void storeMappings(List mappings) { - // try { - // File proxiedStubs = new File("target/stubs") - // proxiedStubs.mkdirs() - // for (StubMapping mapping : mappings) { - // File stub = new File(proxiedStubs, "foo" + ".json") - // stub.createNewFile() - // Files.write(stub.toPath(), mapping.toString().getBytes()) - // } - // } catch (Exception e) { - // throw new RuntimeException(e) - // } - // } - - def "should retrieve pacts from broker using stubrunner options"() throws IOException { - given: - StubRunnerOptions options = new StubRunnerOptionsBuilder() - .withStubRepositoryRoot("pact://https://test.pact.dius.com.au:443") - .withUsername("dXfltyFMgNOFZAxr8io9wJ37iUpY42M") - .withPassword("O5AIZWxelWbLvqMd8PkAVycBJh2Psyg1") - .build() - PactStubDownloader downloader = new PactStubDownloader(options) - when: - Map.Entry entry = downloader - . - downloadAndUnpackStubJar(new StubConfiguration("com.example:bobby:+:classifier")) - then: - entry != null - entry.getValue().exists() - File contracts = new File(entry.getValue(), "com/example/bobby/contracts") - contracts.exists() - contracts.list() != null - contracts.list().size() > 0 - File mappings = new File(entry.getValue(), "com/example/bobby/mappings") - mappings.exists() - mappings.list() != null - mappings.list().size() > 0 - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverterSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverterSpec.groovy deleted file mode 100644 index c7e971b1e7..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverterSpec.groovy +++ /dev/null @@ -1,847 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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.spec.pact - -import java.nio.file.Files - -import au.com.dius.pact.core.model.Pact -import au.com.dius.pact.core.model.PactSpecVersion -import groovy.json.JsonOutput -import org.skyscreamer.jsonassert.JSONAssert -import spock.lang.Issue -import spock.lang.Specification -import spock.lang.Subject - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.TestGenerator -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties -import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter -import org.springframework.core.io.Resource -import org.springframework.core.io.support.PathMatchingResourcePatternResolver - -/** - * @author Marcin Grzejszczak - * @author Tim Ysewyn - */ -class PactContractConverterSpec extends Specification { - - File pactJson = new File(PactContractConverterSpec.getResource("/pact/pact.json"). - toURI()) - File pact509Json = new File(PactContractConverterSpec. - getResource("/pact/pact_509.json").toURI()) - File pactv2Json = new File(PactContractConverterSpec. - getResource("/pact/pact_v2.json").toURI()) - File pactv3Json = new File(PactContractConverterSpec. - getResource("/pact/pact_v3.json").toURI()) - File pactv3Issue889Json = new File(PactContractConverterSpec. - getResource("/pact/pact_v3_issue_889.json").toURI()) - File pactv3MessagingJson = new File(PactContractConverterSpec. - getResource("/pact/pact_v3_messaging.json").toURI()) - File pactv3UnsupportedRuleLogicJson = new File(PactContractConverterSpec. - getResource("/pact/pact_v3_unsupported_rule_logic.json").toURI()) - File pact1043Json = new File(PactContractConverterSpec. - getResource("/pact/for-test-generation/pact_1043.json").toURI()) - File pact1134Json = new File(PactContractConverterSpec. - getResource("/pact/1134/pact_1134.json").toURI()) - @Subject - PactContractConverter converter = new PactContractConverter() - - def "should accept json files that are pact files"() { - expect: - converter.isAccepted(pactJson) - } - - def "should reject json files that are invalid pact files"() { - given: - File invalidPact = new File(PactContractConverterSpec. - getResource("/pact/invalid_pact.json").toURI()) - expect: - !converter.isAccepted(invalidPact) - } - - def "should convert from pact to contract"() { - given: - Contract expectedContract = Contract.make { - description("a retrieve Mallory request a user with username 'username' and password 'password' exists") - request { - method(GET()) - url("/mallory") { - queryParameters { - parameter("name", "ron") - parameter("status", "good") - } - } - headers { - header(contentType(), applicationJson()) - } - body(id: "123", method: "create") - bodyMatchers { - jsonPath('$.id', byRegex("[0-9]{3}")) - } - } - response { - status(200) - headers { - header(contentType(), applicationJson()) - } - body([[ - [email : "rddtGwwWMEhnkAPEmsyE", - id : "eb0f8c17-c06a-479e-9204-14f7c95b63a6", - userName: "AJQrokEGPAVdOHprQpKP"] - ]]) - bodyMatchers { - jsonPath('$[0][*].email', byType()) - jsonPath('$[0][*].id', - byRegex("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")) - jsonPath('$[0]', byType() { - maxOccurrence(5) - }) - jsonPath('$[0][*].userName', byType()) - } - } - } - when: - Collection contracts = converter.convertFrom(pactJson) - then: - contracts == [expectedContract] - } - - @Issue("#509") - def "should convert from pact with matching rules to whole body to contract"() { - given: - Contract expectedContract = Contract.make { - description("a request to POST a person provider accepts a new person") - request { - method(POST()) - url("/user-service/users") - headers { - header(contentType(), applicationJson()) - } - body(firstName: "Arthur", lastName: "Dent") - } - response { - status(201) - headers { - header(contentType(), applicationJsonUtf8()) - } - body(firstName: "Arthur", id: 42, lastName: "Dent") - bodyMatchers { - jsonPath('''$.['firstName']''', byType()) - jsonPath('''$.['id']''', byType()) - jsonPath('''$.['lastName']''', byType()) - } - } - } - when: - Collection contracts = converter.convertFrom(pact509Json) - then: - contracts == [expectedContract] - } - - def "should convert from contract to pact"() { - given: - Collection inputContracts = [ - Contract.make { - name("my_consumer___my_producer___testname") - description("a retrieve Mallory request") - request { - method(GET()) - url("/mallory") { - queryParameters { - parameter("name", "ron") - parameter("status", "good") - } - } - headers { - contentType(applicationJson()) - } - body( - id: 123, - method: $(stub(regex("[0][1][2]"))), - something: "foo" - ) - bodyMatchers { - jsonPath('$.id', byRegex("[0-9]{3}")) - jsonPath('$.something', byEquality()) - } - } - response { - status(200) - headers { - contentType(applicationJson()) - } - body([[ - [email : "rddtGwwWMEhnkAPEmsyE", - id : "eb0f8c17-c06a-479e-9204-14f7c95b63a6", - number : - $(producer(regex("[0-9]{3}")), consumer(923)), - positiveInteger : 1234567890, - negativeInteger : -1234567890, - positiveDecimalNumber: 123.4567890, - negativeDecimalNumber: -123.4567890, - something : "foo", - userName : "AJQrokEGPAVdOHprQpKP", - nullValue : null] - ]]) - bodyMatchers { - jsonPath('$[0][*].email', byType()) - jsonPath('$[0][*].id', - byRegex("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")) - jsonPath('$[0]', byType() { - minOccurrence(1) - maxOccurrence(5) - }) - jsonPath('$[0][*].number', byRegex(number())) - jsonPath('$[0][*].positiveInteger', byRegex(anInteger())) - jsonPath('$[0][*].negativeInteger', byRegex(anInteger())) - jsonPath('$[0][*].positiveDecimalNumber', byRegex(aDouble())) - jsonPath('$[0][*].negativeDecimalNumber', byRegex(aDouble())) - jsonPath('$[0][*].userName', byType()) - jsonPath('$[0][*].something', byEquality()) - jsonPath('$[0][*].nullValue', byNull()) - } - } - } - ] - String expectedJson = ''' -{ - "provider": { - "name": "my_producer" - }, - "consumer": { - "name": "my_consumer" - }, - "interactions": [ - { - "description": "a retrieve Mallory request", - "request": { - "method": "GET", - "path": "\\/mallory", - "query": { - "name": ["ron"], - "status": ["good"] - }, - "headers": { - "Content-Type": "application\\/json" - }, - "body": { - "id": 123, - "method": "012", - "something": "foo" - }, - "matchingRules": { - "body": { - "$.id": { - "matchers": [{ - "match": "regex", - "regex": "[0-9]{3}" - }] - }, - "$.something": { - "matchers": [{ - "match": "equality" - }] - } - } - } - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application\\/json" - }, - "body": [ - [ - { - "email": "rddtGwwWMEhnkAPEmsyE", - "id": "eb0f8c17-c06a-479e-9204-14f7c95b63a6", - "number": 923, - "positiveInteger": 1234567890, - "negativeInteger": -1234567890, - "positiveDecimalNumber": 123.4567890, - "negativeDecimalNumber": -123.4567890, - "userName": "AJQrokEGPAVdOHprQpKP", - "something": "foo", - "nullValue": null - } - ] - ], - "matchingRules": { - "body": { - "$[0][*].email": { - "matchers": [{ - "match": "type" - }] - }, - "$[0][*].id": { - "matchers": [{ - "match": "regex", - "regex": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" - }] - }, - "$[0]": { - "matchers": [{ - "match": "type", - "min": 1, - "max": 5 - }] - }, - "$[0][*].number": { - "matchers": [{ - "match": "number" - }] - }, - "$[0][*].positiveInteger": { - "matchers": [{ - "match": "integer" - }] - }, - "$[0][*].negativeInteger": { - "matchers": [{ - "match": "integer" - }] - }, - "$[0][*].positiveDecimalNumber": { - "matchers": [{ - "match": "decimal" - }] - }, - "$[0][*].negativeDecimalNumber": { - "matchers": [{ - "match": "decimal" - }] - }, - "$[0][*].userName": { - "matchers": [{ - "match": "type" - }] - }, - "$[0][*].something": { - "matchers": [{ - "match": "equality" - }] - }, - "$[0][*].nullValue": { - "matchers": [{ - "match": "null" - }] - } - } - } - } - } - ], - "metadata": { - "pact-jvm": { - "version": "4.3.15" - } - } -} -''' - when: - Pact pact = converter.convertTo(inputContracts).get(0) - then: - String actual = JsonOutput.toJson(pact.toMap(PactSpecVersion.V3)) - JSONAssert.assertEquals(expectedJson, actual, false) - } - - def "should fail to convert from contract to pact when contract has execution property in request"() { - given: - Collection inputContracts = [ - Contract.make { - request { - method(GET()) - url("/mallory") - body( - id: $(c("foo"), p(execute("foo"))) - ) - } - response { - status(200) - - } - } - ] - when: - converter.convertTo(inputContracts) - then: - def e = thrown(UnsupportedOperationException) - e.message.contains("execution property") - } - - def "should fail to convert from contract to pact when contract has execution property in response"() { - given: - Collection inputContracts = [ - Contract.make { - request { - method(GET()) - url("/mallory") - } - response { - status(200) - body( - id: $(c(execute("foo")), p("foo")) - ) - } - } - ] - when: - converter.convertTo(inputContracts) - then: - def e = thrown(UnsupportedOperationException) - e.message.contains("execution property") - } - - def "should convert contracts from samples to pacts"() { - given: - Resource[] contractResources = new PathMatchingResourcePatternResolver(). - getResources("contracts/*.groovy") - Resource[] pactResources = new PathMatchingResourcePatternResolver(). - getResources("contracts/*.json") - Map> contracts = contractResources. - collectEntries { - [(it.filename): ContractVerifierDslConverter. - convertAsCollection(new File("/"), it.getFile())] - } - Map jsonPacts = pactResources. - collectEntries { [(it.filename): it.getFile().text] } - when: - Map> pacts = contracts.entrySet(). - collectEntries { [(it.key): converter.convertTo(it.value)] } - then: - pacts.entrySet().each { - String convertedPactAsText = JsonOutput. - toJson(it.value[0].toMap(PactSpecVersion.V3)) - String pactFileName = it.key.replace("groovy", "json") - println "File name [${it.key}]" - JSONAssert. - assertEquals(jsonPacts.get(pactFileName), convertedPactAsText, true) - } - } - - def "should convert contracts from grouped contracts to pacts"() { - given: - List contracts = ContractVerifierDslConverter. - convertAsCollection(new File("/"), - new File("src/test/resources/contracts/grouped/shouldWorkWithBeer.groovy")) - when: - Collection pacts = converter.convertTo(contracts) - then: - pacts.size() == 1 - String convertedPactAsText = JsonOutput. - toJson(pacts.first().toMap(PactSpecVersion.V3)) - JSONAssert.assertEquals( - new File("src/test/resources/contracts/grouped/shouldWorkWithBeer.json").text, - convertedPactAsText, false) - } - - def "should convert pacts to strings"() { - given: - List contracts = ContractVerifierDslConverter. - convertAsCollection(new File("/"), - new File("src/test/resources/contracts/grouped/shouldWorkWithBeer.groovy")) - and: - Collection pacts = converter.convertTo(contracts) - when: - Map strings = converter.store(pacts) - then: - strings.size() == 1 - strings.keySet().first(). - startsWith("10-04-pact-consumer_10-05-pact-producer_") - strings.keySet().first().endsWith(".json") - JSONAssert.assertEquals( - new File("src/test/resources/contracts/grouped/shouldWorkWithBeer.json").text, - new String(strings.values().first()), false) - } - - def "should convert from pact v2 to two SC contracts"() { - given: - Collection expectedContracts = [ - Contract.make { - description("get all users for max a user with an id named 'user' exists") - request { - method(GET()) - url("/idm/user") - } - response { - status(200) - headers { - header(contentType(), applicationJsonUtf8()) - } - body([[ - [email : "rddtGwwWMEhnkAPEmsyE", - id : "eb0f8c17-c06a-479e-9204-14f7c95b63a6", - userName: "AJQrokEGPAVdOHprQpKP"] - ]]) - bodyMatchers { - jsonPath('$[0][*].email', byType()) - jsonPath('$[0][*].id', - byRegex("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")) - jsonPath('$[0]', byType() { - maxOccurrence(5) - }) - jsonPath('$[0][*].userName', byType()) - } - } - }, - Contract.make { - description("get all users for min a user with an id named 'user' exists") - request { - method(GET()) - url("/idm/user") - } - response { - status(200) - headers { - header(contentType(), applicationJsonUtf8()) - } - body([[ - [email : "DPvAfkCZpOBZWzKYiDMC", - id : "95d0371b-bf30-4943-90a8-8bb1967c4cb2", - userName: "GIUlVKoiLdHLYNKGbcSy"] - ]]) - bodyMatchers { - jsonPath('$[0][*].email', byType()) - jsonPath('$[0][*].id', - byRegex("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")) - jsonPath('$[0]', byType() { - minOccurrence(5) - }) - jsonPath('$[0][*].userName', byType()) - } - } - } - ] - when: - Collection contracts = converter.convertFrom(pactv2Json) - then: - contracts == expectedContracts - } - - def "should convert from pact v3 to three SC contracts"() { - given: - Collection expectedContracts = [ - Contract.make { - description("java test interaction with a DSL array body") - request { - method(GET()) - url("/") - headers { - header(contentType(), applicationJsonUtf8()) - header("Some-Header", - $(c(regex("[a-zA-Z]{9}")), p("someValue"))) - header("someHeaderWithJsonContent", '{"issue":"#595"}') - } - } - response { - status(200) - headers { - header(contentType(), applicationJsonUtf8()) - header("Some-Header", - $(c("someValue"), p(regex("[a-zA-Z]{9}")))) - header("someHeaderWithJsonContent", '{"issue":"#595"}') - } - body([ - [ - "dob" : "07/19/2016", - "id" : 8958464620, - "name" : "Rogger the Dogger", - "timestamp" : "2016-07-19T12:14:39", - "nullValue" : null, - "aNumber" : 1234567890, - "positiveInteger" : 1234567890, - "negativeInteger" : -1234567890, - "positiveDecimalNumber": 123.4567890, - "negativeDecimalNumber": -123.4567890 - ], - [ - "dob" : "07/19/2016", - "id" : 4143398442, - "name" : "Cat in the Hat", - "timestamp" : "2016-07-19T12:14:39", - "nullValue" : null, - "aNumber" : 1234567890, - "positiveInteger" : 1234567890, - "negativeInteger" : -1234567890, - "positiveDecimalNumber": 123.4567890, - "negativeDecimalNumber": -123.4567890 - ] - ]) - bodyMatchers { - jsonPath('$[0].id', byType()) - jsonPath('$[1].id', byType()) - jsonPath('$[*].nullValue', byNull()) - jsonPath('$[*].aNumber', byRegex(number())) - jsonPath('$[*].positiveInteger', byRegex(anInteger())) - jsonPath('$[*].negativeInteger', byRegex(anInteger())) - jsonPath('$[*].positiveDecimalNumber', byRegex(aDouble())) - jsonPath('$[*].negativeDecimalNumber', byRegex(aDouble())) - } - } - }, - Contract.make { - description("test interaction with a array body with templates") - request { - method(GET()) - url("/") - } - response { - status(200) - headers { - header(contentType(), applicationJsonUtf8()) - } - body([ - [ - "dob" : "2016-07-19", - "id" : 1943791933, - "name": "ZSAICmTmiwgFFInuEuiK" - ], - [ - "dob" : "2016-07-19", - "id" : 1943791933, - "name": "ZSAICmTmiwgFFInuEuiK" - ], - [ - "dob" : "2016-07-19", - "id" : 1943791933, - "name": "ZSAICmTmiwgFFInuEuiK" - ] - ]) - bodyMatchers { - jsonPath('$[2].name', byType()) - jsonPath('$[0].id', byType()) - jsonPath('$[1].id', byType()) - jsonPath('$[2].id', byType()) - jsonPath('$[1].name', byType()) - jsonPath('$[0].name', byType()) - jsonPath('$[0].dob', byDate()) - } - } - }, - Contract.make { - description("test interaction with an array like matcher") - request { - method(GET()) - url("/") - } - response { - status(200) - headers { - header(contentType(), applicationJsonUtf8()) - } - body([ - "data": [ - "array1": [[ - "dob" : "2016-07-19", - "id" : 1600309982, - "name": "FVsWAGZTFGPLhWjLuBOd" - ]], - "array2": [[ - "address": "127.0.0.1", - "name" : "jvxrzduZnwwxpFYrQnpd" - ]], - "array3": [[ - [ - "itemCount": 652571349 - ] - ]] - ], - "id" : 7183997828 - ]) - bodyMatchers { - jsonPath('$.data.array3[0]', byType() { - maxOccurrence(5) - }) - jsonPath('$.data.array1', byType() { - minOccurrence(0) - }) - jsonPath('$.data.array2', byType() { - minOccurrence(1) - }) - jsonPath('$.id', byType()) - jsonPath('$.data.array2[*].name', byType()) - jsonPath('$.data.array2[*].address', - byRegex("(\\d{1,3}\\.)+\\d{1,3}")) - jsonPath('$.data.array1[*].name', byType()) - jsonPath('$.data.array1[*].id', byType()) - } - } - } - ] - when: - Collection contracts = converter.convertFrom(pactv3Json) - then: - contracts == expectedContracts - } - - @Issue("#889") - def "should not throw an exception when parsing Pact file with different matchers"() { - when: - converter.convertFrom(pactv3Issue889Json) - then: - noExceptionThrown() - } - - def "should convert from pact v3 messaging to one SC message contract"() { - given: - Collection expectedContracts = [ - Contract.make { - description() - label 'message sent to activemq:output' - input { - triggeredBy('bookReturnedTriggered()') - } - outputMessage { - sentTo 'activemq:output' - body([ - bookName: "foo" - ]) - headers { - header('BOOK-NAME', 'foo') - header(messagingContentType(), applicationJson()) - } - bodyMatchers { - jsonPath('$.bookName', byType()) - } - } - } - ] - when: - Collection contracts = converter.convertFrom(pactv3MessagingJson) - then: - contracts == expectedContracts - } - - def "should fail to convert a pact v3 contract with unsupported rule logic"() { - when: - converter.convertFrom(pactv3UnsupportedRuleLogicJson) - then: - def e = thrown(UnsupportedOperationException) - e.message. - contains("Currently only the AND combination rule logic is supported") - } - - @Issue("1043") - def "should generate a test from pact and not contain a check for an empty array"() { - given: - File output = Files.createTempDirectory("pact").toFile() - output.mkdirs() - when: - new TestGenerator(new ContractVerifierConfigProperties(contractsDslDir: pact1043Json.parentFile, generatedTestSourcesDir: output, generatedTestResourcesDir: output, basePackageForTests: "example")).generate() - then: - File generatedTest = new File(output, "example/ContractVerifierTest.java") - String generatedTestText = generatedTest.text - !generatedTestText.contains('''assertThatJson(parsedJson).array().array("['authors']").isEmpty()''') - } - - @Issue("1134") - def "should work properly with cookies when reading a pact file as contract"() { - given: - File output = Files.createTempDirectory("pact").toFile() - output.mkdirs() - when: - new TestGenerator(new ContractVerifierConfigProperties(contractsDslDir: pact1134Json.parentFile, generatedTestSourcesDir: output, generatedTestResourcesDir: output, basePackageForTests: "example")).generate() - then: - File generatedTest = new File(output, "example/ContractVerifierTest.java") - String generatedTestText = generatedTest.text - generatedTestText.contains('''cookie("a", "1")''') - generatedTestText.contains('''cookie("b", "2")''') - generatedTestText.contains('''assertThat(response.cookie("c")).isNotNull()''') - generatedTestText.contains('''assertThat(response.cookie("c")).isEqualTo("1")''') - generatedTestText.contains('''assertThat(response.cookie("d")).isNotNull()''') - generatedTestText.contains('''assertThat(response.cookie("d")).isEqualTo("2")''') - } - - @Issue("1134") - def "should work properly with cookies when converting contract to pact"() { - given: - Collection expectedContracts = [ - Contract.make { - description("A successful Api GET call get") - request { - method(GET()) - url("/books") - // cause Pact stores cookies in headers - headers { - } - cookies { - cookie("a", "1") - cookie("b", "2") - } - } - response { - status(200) - // cause Pact stores cookies in headers - headers { - } - cookies { - cookie("c", "1") - cookie("d", "2") - } - } - } - ] - when: - Collection contracts = converter.convertFrom(pact1134Json) - then: - contracts == expectedContracts - } - - @Issue("1277") - def "should work properly with json body"() { - when: - converter.convertTo([ - Contract.make { - request { - method 'PUT' - url '/api/admins/1' - body('''{ - "username" : "username", - "password" : "password", - "roles" : [ "ADMIN" ] -}''') - headers { - header('''Content-Type''', '''application/json;charset=UTF-8''') - } - } - response { - status 200 - body('''{ - "admin" : { - "adminId" : 1, - "username" : "username", - "roles" : [ "ADMIN" ] - } -}''') - headers { - header('''Content-Type''', '''application/json;charset=UTF-8''') - } - } - } - ]) - then: - noExceptionThrown() - } -} - - -// file creator -/* -pacts.entrySet().each { - new File("target/${it.key.replace("groovy", "json")}").text = JsonOutput.toJson(it.value.toMap(PactSpecVersion.V3)) -} - */ diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactMetaDataTests.java b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactMetaDataTests.java deleted file mode 100644 index b2bf30dc48..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactMetaDataTests.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2020-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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.spec.pact; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Test; - -class PactMetaDataTests { - - YAMLMapper mapper = new YAMLMapper(); - - @Test - void should_parse_the_metadata_entry() throws JsonProcessingException { - // @formatter:off - String yamlEntry = "" - + "pact:\n" - + " providerStates:\n" - + " - name: state1\n" - + " params:\n" - + " id: 1\n" - + " value: value1\n" - + " - name: state2\n" - + " params:\n" - + " id: 2\n" - + " value: value2"; - // @formatter:on - - PactMetaData metadata = PactMetaData - .fromMetadata(this.mapper.readerForMapOf(Object.class).readValue(yamlEntry)); - - String serialized = this.mapper.writer().forType(PactMetaData.class).writeValueAsString(metadata); - BDDAssertions.then(serialized).isEqualToNormalizingPunctuationAndWhitespace(yamlEntry.replace("pact:\n", "")); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/grouped/shouldWorkWithBeer.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/grouped/shouldWorkWithBeer.groovy deleted file mode 100644 index 97a212e0c2..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/grouped/shouldWorkWithBeer.groovy +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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 contracts.grouped - - -import org.springframework.cloud.contract.spec.Contract - -[ - Contract.make { - description(""" -Represents a successful scenario of getting a beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -``` - -""") - request { - method POST() - name("10-04-pact-consumer___10-05-pact-producer___too young") - url '/check' - body( - age: 60 - ) - headers { - contentType(applicationJson()) - } - bodyMatchers { - jsonPath('$.age', byRegex(regex("[2-9][0-9]"))) - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - contentType(applicationJson()) - } - } - }, - Contract.make { - description(""" -Represents an unsuccessful scenario of getting a beer - -``` -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -``` - -""") - request { - method POST() - name("10-04-pact-consumer___10-05-pact-producer___old enough") - url '/check' - body( - age: 10 - ) - headers { - contentType(applicationJson()) - } - bodyMatchers { - jsonPath('$.age', byRegex(regex("[0-1][0-9]"))) - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - contentType(applicationJson()) - } - bodyMatchers { - jsonPath('$.status', byType()) - } - } - } -] diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/grouped/shouldWorkWithBeer.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/grouped/shouldWorkWithBeer.json deleted file mode 100644 index 610c08b326..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/grouped/shouldWorkWithBeer.json +++ /dev/null @@ -1,153 +0,0 @@ -{ - "provider": { - "name": "10-05-pact-producer" - }, - "consumer": { - "name": "10-04-pact-consumer" - }, - "interactions": [ - { - "description": "\nRepresents an unsuccessful scenario of getting a beer\n\n```\ngiven:\n\tclient is not old enough\nwhen:\n\the applies for a beer\nthen:\n\twe'll NOT grant him the beer\n```\n\n", - "request": { - "method": "POST", - "path": "/check", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "age": 10 - }, - "matchingRules": { - "header": { - "Content-Type": { - "matchers": [ - { - "match": "regex", - "regex": "application/json.*" - } - ], - "combine": "AND" - } - }, - "body": { - "$.age": { - "matchers": [ - { - "match": "regex", - "regex": "[0-1][0-9]" - } - ], - "combine": "AND" - } - } - } - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json" - }, - "body": { - "status": "NOT_OK" - }, - "matchingRules": { - "header": { - "Content-Type": { - "matchers": [ - { - "match": "regex", - "regex": "application/json.*" - } - ], - "combine": "AND" - } - }, - "body": { - "$.status": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - } - } - } - } - }, - { - "description": "\nRepresents a successful scenario of getting a beer\n\n```\ngiven:\n\tclient is old enough\nwhen:\n\the applies for a beer\nthen:\n\twe'll grant him the beer\n```\n\n", - "request": { - "method": "POST", - "path": "/check", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "age": 60 - }, - "matchingRules": { - "header": { - "Content-Type": { - "matchers": [ - { - "match": "regex", - "regex": "application/json.*" - } - ], - "combine": "AND" - } - }, - "body": { - "$.age": { - "matchers": [ - { - "match": "regex", - "regex": "[2-9][0-9]" - } - ], - "combine": "AND" - } - } - } - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json" - }, - "body": { - "status": "OK" - }, - "matchingRules": { - "header": { - "Content-Type": { - "matchers": [ - { - "match": "regex", - "regex": "application/json.*" - } - ], - "combine": "AND" - } - }, - "body": { - "$.status": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - } - } - } - } - } - ], - "metadata": { - "pact-jvm": { - "version": "4.3.15" - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldConvertAllGenerators.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldConvertAllGenerators.groovy deleted file mode 100644 index 3a599d93b4..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldConvertAllGenerators.groovy +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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 contracts - -org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - url '/' - body([ - someInteger : $(c(anyInteger()), p(1234567890)), - someDecimal : $(c(anyDouble()), p(123.123)), - someHex : $(c(anyHex()), p('DEADC0DE')), - someAlphaNumeric: - $(c(anyAlphaNumeric()), p('Some alpha numeric string with 1234567890')), - someUUID : $(c(anyUuid()), p('00000000-0000-0000-0000-000000000000')), - someDate : $(c(anyDate()), p('2018-03-26')), - someTime : $(c(anyTime()), p('13:37:00')), - someDateTime : $(c(anyDateTime()), p('2018-03-26 13:37:00')), - someBoolean : $(c(anyBoolean()), p('true')), - someRegex : $(c(regex('[0-9]{10}')), p(1234567890)) - ]) - headers { - contentType('application/json') - } - } - response { - status OK() - body([ - someInteger : $(c(1234567890), p(anyInteger())), - someDecimal : $(c(123.123), p(anyDouble())), - someHex : $(c('DEADC0DE'), p(anyHex())), - someAlphaNumeric: - $(c('Some alpha numeric string with 1234567890'), p(anyAlphaNumeric())), - someUUID : $(c('00000000-0000-0000-0000-000000000000'), p(anyUuid())), - someDate : $(c('2018-03-26'), p(anyDate())), - someTime : $(c('13:37:00'), p(anyTime())), - someDateTime : $(c('2018-03-26 13:37:00'), p(anyDateTime())), - someBoolean : $(c('true'), p(anyBoolean())), - someRegex : $(c(1234567890), p(regex('[0-9]{10}'))) - ]) - headers { - contentType('application/json') - } - } - metadata([ - pact: [ - providerStates: - [ - [ - name: "someState1", - params: [ - id: 1, - value: "someValue1" - ] - ], - [ - name: "someState2", - params: [ - id: 2, - value: "someValue2" - ] - ] - ] - ] - ]) -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldConvertAllGenerators.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldConvertAllGenerators.json deleted file mode 100644 index 406d3bde8f..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldConvertAllGenerators.json +++ /dev/null @@ -1,296 +0,0 @@ -{ - "provider": { - "name": "Provider" - }, - "consumer": { - "name": "Consumer" - }, - "interactions": [ - { - "description": "", - "request": { - "method": "POST", - "path": "/", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "someInteger": 1234567890, - "someDecimal": 123.123, - "someHex": "DEADC0DE", - "someAlphaNumeric": "Some alpha numeric string with 1234567890", - "someUUID": "00000000-0000-0000-0000-000000000000", - "someDate": "2018-03-26", - "someTime": "13:37:00", - "someDateTime": "2018-03-26 13:37:00", - "someBoolean": "true", - "someRegex": 1234567890 - }, - "generators": { - "body": { - "$.someInteger": { - "type": "RandomInt", - "min": 0, - "max": 2147483647 - }, - "$.someDecimal": { - "type": "RandomDecimal", - "digits": 10 - }, - "$.someHex": { - "type": "RandomHexadecimal", - "digits": 10 - }, - "$.someAlphaNumeric": { - "type": "RandomString", - "size": 10 - }, - "$.someUUID": { - "type": "Uuid" - }, - "$.someDate": { - "type": "Date" - }, - "$.someTime": { - "type": "Time" - }, - "$.someDateTime": { - "type": "DateTime" - }, - "$.someBoolean": { - "type": "RandomBoolean" - }, - "$.someRegex": { - "type": "Regex", - "regex": "[0-9]{10}" - } - } - }, - "matchingRules": { - "header": { - "Content-Type": { - "matchers": [ - { - "match": "regex", - "regex": "application/json.*" - } - ], - "combine": "AND" - } - }, - "body": { - "$.someHex": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - }, - "$.someAlphaNumeric": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - }, - "$.someUUID": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - }, - "$.someDate": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - }, - "$.someTime": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - }, - "$.someDateTime": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - }, - "$.someBoolean": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - } - } - } - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json" - }, - "body": { - "someInteger": 1234567890, - "someDecimal": 123.123, - "someHex": "DEADC0DE", - "someAlphaNumeric": "Some alpha numeric string with 1234567890", - "someUUID": "00000000-0000-0000-0000-000000000000", - "someDate": "2018-03-26", - "someTime": "13:37:00", - "someDateTime": "2018-03-26 13:37:00", - "someBoolean": "true", - "someRegex": 1234567890 - }, - "generators": { - "body": { - "$.someInteger": { - "type": "RandomInt", - "min": 0, - "max": 2147483647 - }, - "$.someDecimal": { - "type": "RandomDecimal", - "digits": 10 - }, - "$.someHex": { - "type": "RandomHexadecimal", - "digits": 10 - }, - "$.someAlphaNumeric": { - "type": "RandomString", - "size": 10 - }, - "$.someUUID": { - "type": "Uuid" - }, - "$.someDate": { - "type": "Date" - }, - "$.someTime": { - "type": "Time" - }, - "$.someDateTime": { - "type": "DateTime" - }, - "$.someBoolean": { - "type": "RandomBoolean" - }, - "$.someRegex": { - "type": "Regex", - "regex": "[0-9]{10}" - } - } - }, - "matchingRules": { - "header": { - "Content-Type": { - "matchers": [ - { - "match": "regex", - "regex": "application/json.*" - } - ], - "combine": "AND" - } - }, - "body": { - "$.someHex": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - }, - "$.someAlphaNumeric": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - }, - "$.someUUID": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - }, - "$.someDate": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - }, - "$.someTime": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - }, - "$.someDateTime": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - }, - "$.someBoolean": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - } - } - } - }, - "providerStates": [ - { - "name": "someState1", - "params": { - "id": 1, - "value": "someValue1" - } - }, - { - "name": "someState2", - "params": { - "id": 2, - "value": "someValue2" - } - } - ] - } - ], - "metadata": { - "pactSpecification": { - "version": "3.0.0" - }, - "pact-jvm": { - "version": "4.3.15" - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsFraud.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsFraud.groovy deleted file mode 100644 index fb4127538f..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsFraud.groovy +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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 contracts - -org.springframework.cloud.contract.spec.Contract.make { - request { // (1) - method 'PUT' // (2) - url '/fraudcheck' // (3) - body([ // (4) - clientId : $(c(regex('[0-9]{10}')), p("8532032713")), - loanAmount: 99999 - ]) - headers { // (5) - contentType('application/vnd.fraud.v1+json') - } - } - response { // (6) - status OK() // (7) - body([ // (8) - fraudCheckStatus: "FRAUD", - rejectionReason : "Amount too high" - ]) - headers { // (9) - contentType('application/vnd.fraud.v1+json') - } - } -} - -/* -Since we don't want to force on the user to hardcode values of fields that are dynamic -(timestamps, database ids etc.), one can parametrize those entries. If you wrap your field's - value in a `$(...)` or `value(...)` and provide a dynamic value of a field then - the concrete value will be generated for you. If you want to be really explicit about - which side gets which value you can do that by using the `value(consumer(...), producer(...))` notation. - That way what's present in the `consumer` section will end up in the produced stub. What's - there in the `producer` will end up in the autogenerated test. If you provide only the - regular expression side without the concrete value then Spring Cloud Contract will generate one for you. - -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` that matches a regular expression `[0-9]{10}` - * has a field `loanAmount` that is equal to `99999` -(5) - with header `Content-Type` equal to `application/vnd.fraud.v1+json` -(6) - then the response will be sent with -(7) - status equal `200` -(8) - and JSON body equal to - { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" } -(9) - with header `Content-Type` equal to `application/vnd.fraud.v1+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` that will have a generated value that matches a regular expression `[0-9]{10}` - * has a field `loanAmount` that is equal to `99999` -(5) - with header `Content-Type` equal to `application/vnd.fraud.v1+json` -(6) - then the test will assert if the response has been sent with -(7) - status equal `200` -(8) - and JSON body equal to - { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" } -(9) - with header `Content-Type` matching `application/vnd.fraud.v1+json.*` - */ diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsFraud.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsFraud.json deleted file mode 100644 index 65e06360f4..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsFraud.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "provider": { - "name": "Provider" - }, - "consumer": { - "name": "Consumer" - }, - "interactions": [ - { - "description": "", - "request": { - "method": "PUT", - "path": "/fraudcheck", - "headers": { - "Content-Type": "application/vnd.fraud.v1+json" - }, - "body": { - "clientId": "8532032713", - "loanAmount": 99999 - }, - "generators": { - "body": { - "$.clientId": { - "type": "Regex", - "regex": "[0-9]{10}" - } - } - }, - "matchingRules": { - "header": { - "Content-Type": { - "matchers": [ - { - "match": "regex", - "regex": "application/vnd\\.fraud\\.v1\\+json.*" - } - ], - "combine": "AND" - } - }, - "body": { - "$.clientId": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - } - } - } - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/vnd.fraud.v1+json" - }, - "body": { - "fraudCheckStatus": "FRAUD", - "rejectionReason": "Amount too high" - }, - "matchingRules": { - "header": { - "Content-Type": { - "matchers": [ - { - "match": "regex", - "regex": "application/vnd\\.fraud\\.v1\\+json.*" - } - ], - "combine": "AND" - } - }, - "body": { - "$.fraudCheckStatus": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - }, - "$.rejectionReason": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - } - } - } - } - } - ], - "metadata": { - "pactSpecification": { - "version": "3.0.0" - }, - "pact-jvm": { - "version": "4.3.15" - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.groovy deleted file mode 100644 index 0059e41c3f..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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 contracts - -org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url '/fraudcheck' - body(""" - { - "clientId":"${ - value(consumer(regex('[0-9]{10}')), producer('1234567890')) - }", - "loanAmount":123.123 - } - """ - ) - headers { - contentType("application/vnd.fraud.v1+json") - } - - } - response { - status OK() - body( - fraudCheckStatus: "OK", - rejectionReason: $(consumer(null), - producer(execute('assertThatRejectionReasonIsNull($it)'))) - ) - headers { - contentType("application/vnd.fraud.v1+json") - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.json deleted file mode 100644 index 672a9ef561..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "provider": { - "name": "Provider" - }, - "consumer": { - "name": "Consumer" - }, - "interactions": [ - { - "description": "", - "request": { - "method": "PUT", - "path": "/fraudcheck", - "headers": { - "Content-Type": "application/vnd.fraud.v1+json" - }, - "body": { - "clientId": "1234567890", - "loanAmount": 123.123 - }, - "generators": { - "body": { - "$.clientId": { - "type": "Regex", - "regex": "[0-9]{10}" - } - } - }, - "matchingRules": { - "header": { - "Content-Type": { - "matchers": [ - { - "match": "regex", - "regex": "application/vnd\\.fraud\\.v1\\+json.*" - } - ], - "combine": "AND" - } - }, - "body": { - "$.clientId": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - } - } - } - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/vnd.fraud.v1+json" - }, - "body": { - "fraudCheckStatus": "OK", - "rejectionReason": null - }, - "matchingRules": { - "header": { - "Content-Type": { - "matchers": [ - { - "match": "regex", - "regex": "application/vnd\\.fraud\\.v1\\+json.*" - } - ], - "combine": "AND" - } - }, - "body": { - "$.fraudCheckStatus": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - } - } - } - } - } - ], - "metadata": { - "pactSpecification": { - "version": "3.0.0" - }, - "pact-jvm": { - "version": "4.3.15" - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldReturnFraudStats.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldReturnFraudStats.groovy deleted file mode 100644 index 2b59b976da..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldReturnFraudStats.groovy +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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 contracts - -import org.springframework.cloud.contract.spec.Contract - -[ - Contract.make { - request { - name "should count all frauds" - method GET() - url '/frauds' - } - response { - status OK() - body([ - count: 200 - ]) - headers { - contentType("application/vnd.fraud.v1+json") - } - } - }, - Contract.make { - request { - method GET() - url '/drunks' - } - response { - status OK() - body([ - count: 100 - ]) - headers { - contentType("application/vnd.fraud.v1+json") - } - } - } -] diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldReturnFraudStats.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldReturnFraudStats.json deleted file mode 100644 index 9ec4725556..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldReturnFraudStats.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "provider": { - "name": "Provider" - }, - "consumer": { - "name": "Consumer" - }, - "interactions": [ - { - "description": "", - "request": { - "method": "GET", - "path": "/frauds" - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/vnd.fraud.v1+json" - }, - "body": { - "count": 200 - }, - "matchingRules": { - "header": { - "Content-Type": { - "matchers": [ - { - "match": "regex", - "regex": "application/vnd\\.fraud\\.v1\\+json.*" - } - ], - "combine": "AND" - } - } - } - } - }, - { - "description": "", - "request": { - "method": "GET", - "path": "/drunks" - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/vnd.fraud.v1+json" - }, - "body": { - "count": 100 - }, - "matchingRules": { - "header": { - "Content-Type": { - "matchers": [ - { - "match": "regex", - "regex": "application/vnd\\.fraud\\.v1\\+json.*" - } - ], - "combine": "AND" - } - } - } - } - } - ], - "metadata": { - "pactSpecification": { - "version": "3.0.0" - }, - "pact-jvm": { - "version": "4.3.15" - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldSendMessageWhenBookReturned.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldSendMessageWhenBookReturned.groovy deleted file mode 100644 index c6858397ff..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldSendMessageWhenBookReturned.groovy +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013-2020 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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 contracts - -import org.springframework.cloud.contract.spec.Contract - -[ - Contract.make { - label 'some_label' - input { - triggeredBy('bookReturnedTriggered()') - } - outputMessage { - sentTo('activemq:output') - body('''{ "bookName" : "foo" }''') - headers { - header('BOOK-NAME', 'foo') - messagingContentType(applicationJson()) - } - } - } -] diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldSendMessageWhenBookReturned.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldSendMessageWhenBookReturned.json deleted file mode 100644 index 87d265e569..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldSendMessageWhenBookReturned.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "consumer": { - "name": "Consumer" - }, - "provider": { - "name": "Provider" - }, - "messages": [ - { - "description": "message sent to activemq:output", - "metaData": { - "BOOK-NAME": "foo", - "contentType": "application/json" - }, - "contents": { - "bookName": "foo" - }, - "providerStates": [ - { - "name": "bookReturnedTriggered()" - } - ], - "matchingRules": { - "body": { - "$.bookName": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - } - } - } - } - ], - "metadata": { - "pactSpecification": { - "version": "3.0.0" - }, - "pact-jvm": { - "version": "4.3.15" - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/1134/pact_1134.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/1134/pact_1134.json deleted file mode 100644 index 7e1cdaf008..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/1134/pact_1134.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "provider": { - "name": "cookie-service" - }, - "consumer": { - "name": "cookie-consumer" - }, - "interactions": [ - { - "description": "A successful Api GET call", - "request": { - "method": "GET", - "path": "/books", - "headers": { - "Cookie": "a=1;b=2" - } - }, - "response": { - "status": 200, - "headers": { - "Cookie": "c=1;d=2" - } - }, - "providerStates": [ - { - "name": "get" - } - ] - } - ], - "metadata": { - "pact-specification": { - "version": "3.0.0" - }, - "pact-jvm": { - "version": "3.5.13" - } - } -} \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/for-test-generation/pact_1043.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/for-test-generation/pact_1043.json deleted file mode 100644 index ddde77f180..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/for-test-generation/pact_1043.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "provider": { - "name": "book-catalog-service" - }, - "consumer": { - "name": "books-client-catalog-rest-consumer" - }, - "interactions": [ - { - "description": "A successful Api GET call", - "request": { - "method": "GET", - "path": "/books", - "headers": { - "Content-Type": "application/json;charset=UTF-8" - } - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json;charset=UTF-8" - }, - "body": [ - { - "isbn": "978-3-86680-192-9", - "id": 100, - "title": "A book", - "authors": [ - { - "firstName": "string", - "lastName": "string" - } - ] - } - ], - "matchingRules": { - "body": { - "$[0].id": { - "matchers": [ - { - "match": "integer" - } - ], - "combine": "AND" - }, - "$[0].title": { - "matchers": [ - { - "match": "regex", - "regex": ".*" - } - ], - "combine": "AND" - }, - "$[0].authors[0].firstName": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - }, - "$[0].authors[0].lastName": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - }, - "$[0].isbn": { - "matchers": [ - { - "match": "regex", - "regex": "[0-9]{3}-[0-9]{1}-[0-9]{5}-[0-9]{3}-[0-9]{1}" - } - ], - "combine": "AND" - } - } - }, - "generators": { - "body": { - "$[0].id": { - "type": "RandomInt", - "min": 0, - "max": 2147483647 - }, - "$[0].authors[0].firstName": { - "type": "RandomString", - "size": 20 - }, - "$[0].authors[0].lastName": { - "type": "RandomString", - "size": 20 - } - } - } - }, - "providerStates": [ - { - "name": "get" - } - ] - } - ], - "metadata": { - "pact-specification": { - "version": "3.0.0" - }, - "pact-jvm": { - "version": "3.5.13" - } - } -} \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/invalid_pact.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/invalid_pact.json deleted file mode 100644 index ee68c7e154..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/invalid_pact.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "some": "json" -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact.json deleted file mode 100644 index bf7cee45a3..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "provider": { - "name": "Alice Service" - }, - "consumer": { - "name": "Consumer" - }, - "interactions": [ - { - "description": "a retrieve Mallory request", - "provider_state": "a user with username 'username' and password 'password' exists", - "request": { - "method": "GET", - "path": "/mallory", - "query": "name=ron&status=good", - "body": { - "id": "123", - "method": "create" - }, - "headers": { - "Content-Type": "application/json" - }, - "matchingRules": { - "$.body.id": { - "match": "regex", - "regex": "[0-9]{3}" - } - } - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json" - }, - "body": [ - [ - { - "email": "rddtGwwWMEhnkAPEmsyE", - "id": "eb0f8c17-c06a-479e-9204-14f7c95b63a6", - "userName": "AJQrokEGPAVdOHprQpKP" - } - ] - ], - "matchingRules": { - "$.body[0][*].email": { - "match": "type" - }, - "$.body[0][*].id": { - "regex": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" - }, - "$.body[0]": { - "max": 5, - "match": "type" - }, - "$.body[0][*].userName": { - "match": "type" - } - } - } - } - ] -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_509.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_509.json deleted file mode 100644 index 1cf2d41493..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_509.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "consumer": { - "name": "ui" - }, - "provider": { - "name": "userservice" - }, - "interactions": [ - { - "description": "a request to POST a person", - "providerState": "provider accepts a new person", - "request": { - "method": "POST", - "path": "/user-service/users", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "firstName": "Arthur", - "lastName": "Dent" - } - }, - "response": { - "status": 201, - "headers": { - "Content-Type": "application/json;charset=UTF-8" - }, - "body": { - "id": 42, - "firstName": "Arthur", - "lastName": "Dent" - }, - "matchingRules": { - "$.body": { - "match": "type" - } - } - } - } - ], - "metadata": { - "pactSpecification": { - "version": "2.0.0" - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v2.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v2.json deleted file mode 100644 index 31567ad63a..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v2.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "provider": { - "name": "266_provider" - }, - "consumer": { - "name": "test_consumer" - }, - "interactions": [ - { - "description": "get all users for max", - "request": { - "method": "GET", - "path": "/idm/user" - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json;charset=UTF-8" - }, - "body": [ - [ - { - "email": "rddtGwwWMEhnkAPEmsyE", - "id": "eb0f8c17-c06a-479e-9204-14f7c95b63a6", - "userName": "AJQrokEGPAVdOHprQpKP" - } - ] - ], - "matchingRules": { - "$.body[0][*].email": { - "match": "type" - }, - "$.body[0][*].id": { - "regex": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" - }, - "$.body[0]": { - "max": 5, - "match": "type" - }, - "$.body[0][*].userName": { - "match": "type" - } - } - }, - "providerState": "a user with an id named 'user' exists" - }, - { - "description": "get all users for min", - "request": { - "method": "GET", - "path": "/idm/user" - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json;charset=UTF-8" - }, - "body": [ - [ - { - "email": "DPvAfkCZpOBZWzKYiDMC", - "id": "95d0371b-bf30-4943-90a8-8bb1967c4cb2", - "userName": "GIUlVKoiLdHLYNKGbcSy" - } - ] - ], - "matchingRules": { - "$.body[0][*].email": { - "match": "type" - }, - "$.body[0][*].id": { - "regex": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" - }, - "$.body[0]": { - "min": 5, - "match": "type" - }, - "$.body[0][*].userName": { - "match": "type" - } - } - }, - "providerState": "a user with an id named 'user' exists" - } - ], - "metadata": { - "pact-specification": { - "version": "2.0.0" - }, - "pact-jvm": { - "version": "3.2.11" - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v3.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v3.json deleted file mode 100644 index 18e3702168..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v3.json +++ /dev/null @@ -1,330 +0,0 @@ -{ - "provider": { - "name": "test_provider_array" - }, - "consumer": { - "name": "test_consumer_array" - }, - "interactions": [ - { - "description": "java test interaction with a DSL array body", - "request": { - "method": "GET", - "path": "/", - "headers": { - "Content-Type": "application/json;charset=UTF-8", - "Some-Header": "someValue", - "someHeaderWithJsonContent": "{\"issue\":\"#595\"}" - }, - "matchingRules": { - "header": { - "Some-Header": { - "matchers": [ - { - "match": "regex", - "regex": "[a-zA-Z]{9}" - } - ] - } - } - } - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json;charset=UTF-8", - "Some-Header": "someValue", - "someHeaderWithJsonContent": "{\"issue\":\"#595\"}" - }, - "body": [ - { - "dob": "07/19/2016", - "id": 8958464620, - "name": "Rogger the Dogger", - "timestamp": "2016-07-19T12:14:39", - "nullValue": null, - "aNumber": 1234567890, - "positiveInteger": 1234567890, - "negativeInteger": -1234567890, - "positiveDecimalNumber": 123.4567890, - "negativeDecimalNumber": -123.4567890 - }, - { - "dob": "07/19/2016", - "id": 4143398442, - "name": "Cat in the Hat", - "timestamp": "2016-07-19T12:14:39", - "nullValue": null, - "aNumber": 1234567890, - "positiveInteger": 1234567890, - "negativeInteger": -1234567890, - "positiveDecimalNumber": 123.4567890, - "negativeDecimalNumber": -123.4567890 - } - ], - "matchingRules": { - "header": { - "Some-Header": { - "matchers": [ - { - "match": "regex", - "regex": "[a-zA-Z]{9}" - } - ] - } - }, - "body": { - "$[0].id": { - "matchers": [ - { - "match": "type" - } - ] - }, - "$[1].id": { - "matchers": [ - { - "match": "type" - } - ] - }, - "$[*].nullValue": { - "matchers": [ - { - "match": "null" - } - ] - }, - "$[*].aNumber": { - "matchers": [ - { - "match": "number" - } - ] - }, - "$[*].positiveInteger": { - "matchers": [ - { - "match": "integer" - } - ] - }, - "$[*].negativeInteger": { - "matchers": [ - { - "match": "integer" - } - ] - }, - "$[*].positiveDecimalNumber": { - "matchers": [ - { - "match": "decimal" - } - ] - }, - "$[*].negativeDecimalNumber": { - "matchers": [ - { - "match": "decimal" - } - ] - } - } - } - } - }, - { - "description": "test interaction with a array body with templates", - "request": { - "method": "GET", - "path": "/" - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json;charset=UTF-8" - }, - "body": [ - { - "dob": "2016-07-19", - "id": 1943791933, - "name": "ZSAICmTmiwgFFInuEuiK" - }, - { - "dob": "2016-07-19", - "id": 1943791933, - "name": "ZSAICmTmiwgFFInuEuiK" - }, - { - "dob": "2016-07-19", - "id": 1943791933, - "name": "ZSAICmTmiwgFFInuEuiK" - } - ], - "matchingRules": { - "body": { - "$[2].name": { - "matchers": [ - { - "match": "type" - } - ] - }, - "$[0].id": { - "matchers": [ - { - "match": "type" - } - ] - }, - "$[1].id": { - "matchers": [ - { - "match": "type" - } - ] - }, - "$[2].id": { - "matchers": [ - { - "match": "type" - } - ] - }, - "$[1].name": { - "matchers": [ - { - "match": "type" - } - ] - }, - "$[0].name": { - "matchers": [ - { - "match": "type" - } - ] - }, - "$[0].dob": { - "matchers": [ - { - "date": "yyyy-MM-dd" - } - ] - } - } - } - } - }, - { - "description": "test interaction with an array like matcher", - "request": { - "method": "GET", - "path": "/" - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json;charset=UTF-8" - }, - "body": { - "data": { - "array1": [ - { - "dob": "2016-07-19", - "id": 1600309982, - "name": "FVsWAGZTFGPLhWjLuBOd" - } - ], - "array2": [ - { - "address": "127.0.0.1", - "name": "jvxrzduZnwwxpFYrQnpd" - } - ], - "array3": [ - [ - { - "itemCount": 652571349 - } - ] - ] - }, - "id": 7183997828 - }, - "matchingRules": { - "body": { - "$.data.array3[0]": { - "matchers": [ - { - "max": 5, - "match": "type" - } - ] - }, - "$.data.array1": { - "matchers": [ - { - "min": 0, - "match": "type" - } - ] - }, - "$.data.array2": { - "matchers": [ - { - "min": 1, - "match": "type" - } - ] - }, - "$.id": { - "matchers": [ - { - "match": "type" - } - ] - }, - "$.data.array2[*].name": { - "matchers": [ - { - "match": "type" - } - ] - }, - "$.data.array2[*].address": { - "matchers": [ - { - "regex": "(\\d{1,3}\\.)+\\d{1,3}" - } - ] - }, - "$.data.array1[*].name": { - "matchers": [ - { - "match": "type" - } - ] - }, - "$.data.array1[*].id": { - "matchers": [ - { - "match": "type" - } - ] - } - } - } - } - } - ], - "metadata": { - "pact-specification": { - "version": "3.0.0" - }, - "pact-jvm": { - "version": "3.2.11" - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v3_issue_889.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v3_issue_889.json deleted file mode 100644 index aeed8c4906..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v3_issue_889.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "consumer": { - "name": "order-manager" - }, - "provider": { - "name": "lineitem-worker" - }, - "messages": [ - { - "description": "A message sent to order-exchange", - "metaData": { - "sentTo": "order-exchange" - }, - "contents": { - "lineItemId": "string", - "orderId": "XXX-XXXXXX-000000-0000C", - "timestamp": 1550500138678, - "marketId": "MRKTDE", - "status": "PROCESSED" - }, - "providerStates": [ - { - "name": "statusMessageCreated()" - } - ], - "matchingRules": { - "body": { - "$.timestamp": { - "matchers": [ - { - "match": "number" - } - ], - "combine": "AND" - }, - "$.lineItemId": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - }, - "$.orderId": { - "matchers": [ - { - "match": "regex", - "regex": "[A-Z]{3}-[A-Z]{6}-[0-9]{6}-[0-9A-F]{5}" - } - ], - "combine": "AND" - }, - "$.marketId": { - "matchers": [ - { - "match": "regex", - "regex": "[A-Z]{6}" - } - ], - "combine": "AND" - }, - "$.status": { - "matchers": [ - { - "match": "regex", - "regex": "[A-Z,_]*" - } - ], - "combine": "AND" - } - } - } - } - ], - "metadata": { - "pact-specification": { - "version": "3.0.0" - }, - "pact-jvm": { - "version": "3.5.13" - } - } -} \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v3_messaging.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v3_messaging.json deleted file mode 100644 index a06f5835dc..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v3_messaging.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "consumer": { - "name": "Consumer" - }, - "provider": { - "name": "Provider" - }, - "messages": [ - { - "description": "message sent to activemq:output", - "metaData": { - "sentTo": "activemq:output", - "BOOK-NAME": "foo", - "contentType": "application/json" - }, - "contents": { - "bookName": "foo" - }, - "providerStates": [ - { - "name": "bookReturnedTriggered()" - } - ], - "matchingRules": { - "body": { - "$.bookName": { - "matchers": [ - { - "match": "type" - } - ], - "combine": "AND" - } - } - } - } - ], - "metadata": { - "pact-specification": { - "version": "3.0.0" - }, - "pact-jvm": { - "version": "3.5.13" - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v3_unsupported_rule_logic.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v3_unsupported_rule_logic.json deleted file mode 100644 index 7c60020a78..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v3_unsupported_rule_logic.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "provider": { - "name": "test_unsupported_rule_logic" - }, - "consumer": { - "name": "test_unsupported_rule_logic" - }, - "interactions": [ - { - "description": "test unsupported rule logic", - "request": { - "method": "GET", - "path": "/" - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json;charset=UTF-8" - }, - "body": [ - { - "optionalField": 1234567890 - } - ], - "matchingRules": { - "body": { - "$[*].optionalField": { - "matchers": [ - { - "match": "integer" - }, - { - "match": "null" - } - ], - "combine": "OR" - } - } - } - } - } - ], - "metadata": { - "pact-specification": { - "version": "3.0.0" - }, - "pact-jvm": { - "version": "3.2.11" - } - } -}