From 6402e14f3c588b85fba542d5ecc007736b7ebbbd Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Mon, 2 Apr 2018 22:50:40 +0200 Subject: [PATCH] Added support for Stub Runner and Pact Broker fixes gh-191 commit 533f1d3d0e8f6dcd37677bfef555fc2ea86bc1b1 Author: Tim Ysewyn Date: Wed Mar 7 15:56:48 2018 +0100 Upgraded pact-jvm-model to 3.5.13 --- docs/src/main/asciidoc/verifier_contract.adoc | 74 ++++ docs/src/main/asciidoc/verifier_faq.adoc | 190 ++++++++- pom.xml | 11 + .../contracts/com/example/server/pom.xml | 2 +- .../standalone/dsl/http-client/build.gradle | 2 +- samples/standalone/dsl/http-client/pom.xml | 2 +- .../src/test/resources/application.yaml | 1 + .../standalone/dsl/http-server/build.gradle | 2 +- samples/standalone/dsl/http-server/pom.xml | 2 +- .../messaging/stream-sink/build.gradle | 2 +- .../standalone/messaging/stream-sink/pom.xml | 2 +- .../messaging/stream-source/build.gradle | 2 +- .../messaging/stream-source/pom.xml | 2 +- .../pact/pact-http-client/build.gradle | 4 +- .../standalone/pact/pact-http-client/pom.xml | 4 +- .../pact/pact-http-server/build.gradle | 4 +- .../standalone/pact/pact-http-server/pom.xml | 4 +- .../restdocs/http-client/build.gradle | 2 +- .../standalone/restdocs/http-client/pom.xml | 2 +- .../restdocs/http-server/build.gradle | 2 +- .../standalone/restdocs/http-server/pom.xml | 2 +- .../webclient/http-client/build.gradle | 2 +- .../standalone/webclient/http-client/pom.xml | 2 +- .../webclient/http-server/build.gradle | 2 +- .../standalone/yml/http-client/build.gradle | 2 +- samples/standalone/yml/http-client/pom.xml | 2 +- .../standalone/yml/http-server/build.gradle | 2 +- samples/standalone/yml/http-server/pom.xml | 2 +- spring-cloud-contract-dependencies/pom.xml | 2 +- .../stubrunner/AetherStubDownloader.java | 2 +- .../stubrunner/ContractDownloader.java | 8 +- .../stubrunner/ScmStubDownloaderBuilder.java | 2 +- .../stubrunner/StubConfiguration.java | 2 +- .../stubrunner/StubRunnerPropertyUtils.java | 9 + .../stubrunner/TemporaryFileStorage.java | 2 +- .../StubRunnerPropertyUtilsSpec.groovy | 28 ++ spring-cloud-contract-tools/pom.xml | 2 +- .../pom.xml | 2 +- .../verifier/MavenContractsDownloader.java | 2 +- .../src/test/projects/pact/pom.xml | 2 +- .../pom.xml | 26 +- .../stubrunner/PactStubDownloaderBuilder.java | 376 ++++++++++++++++++ .../verifier/spec/pact/BodyConverter.groovy | 0 .../spec/pact/MatchingRulesConverter.groovy | 0 .../spec/pact/MessagePactCreator.groovy | 0 .../pact/MessagingSCContractCreator.groovy | 0 .../spec/pact/PactContractConverter.groovy | 0 .../pact/RequestResponsePactCreator.groovy | 0 .../RequestResponseSCContractCreator.groovy | 0 .../spec/pact/ValueGeneratorConverter.groovy | 0 .../main/resources/META-INF/spring.factories | 5 + .../PactStubDownloaderBuilderSpec.groovy | 114 ++++++ .../pact/PactContractConverterSpec.groovy | 0 .../shouldConvertAllGenerators.groovy | 0 .../contracts/shouldConvertAllGenerators.json | 0 .../contracts/shouldMarkClientAsFraud.groovy | 0 .../contracts/shouldMarkClientAsFraud.json | 0 .../shouldMarkClientAsNotFraud.groovy | 0 .../contracts/shouldMarkClientAsNotFraud.json | 0 .../contracts/shouldReturnFraudStats.groovy | 0 .../contracts/shouldReturnFraudStats.json | 0 .../shouldSendMessageWhenBookReturned.groovy | 0 .../shouldSendMessageWhenBookReturned.json | 0 ...houldSendMessageWhenMessageReceived.groovy | 0 .../shouldSendMessageWhenMessageReceived.json | 0 .../shouldVerifyWhenBookWasDeleted.groovy | 0 .../shouldVerifyWhenBookWasDeleted.json | 0 .../src/test/resources/pact/invalid_pact.json | 0 .../src/test/resources/pact/pact.json | 0 .../src/test/resources/pact/pact_509.json | 0 .../src/test/resources/pact/pact_v2.json | 0 .../src/test/resources/pact/pact_v3.json | 0 .../resources/pact/pact_v3_messaging.json | 0 .../pact/pact_v3_unsupported_rule_logic.json | 0 .../main/resources/META-INF/spring.factories | 2 - .../contracts/shouldConvertAllMatchers.groovy | 68 ---- .../contracts/shouldConvertAllMatchers.json | 276 ------------- .../contract/verifier/TestGenerator.groovy | 6 + .../verifier/file/ContractFileScanner.groovy | 29 +- .../file/ContractFileScannerSpec.groovy | 25 +- .../directory/with/mixed/invalid.json | 23 ++ .../contract/wiremock/WireMockSpring.java | 3 +- 82 files changed, 953 insertions(+), 395 deletions(-) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/pom.xml (71%) create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/stubrunner/PactStubDownloaderBuilder.java rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/BodyConverter.groovy (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/MatchingRulesConverter.groovy (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/MessagePactCreator.groovy (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/MessagingSCContractCreator.groovy (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverter.groovy (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/RequestResponsePactCreator.groovy (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/RequestResponseSCContractCreator.groovy (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/ValueGeneratorConverter.groovy (100%) create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/resources/META-INF/spring.factories create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/groovy/org/springframework/cloud/contract/stubrunner/PactStubDownloaderBuilderSpec.groovy rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverterSpec.groovy (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/contracts/shouldConvertAllGenerators.groovy (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/contracts/shouldConvertAllGenerators.json (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/contracts/shouldMarkClientAsFraud.groovy (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/contracts/shouldMarkClientAsFraud.json (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/contracts/shouldMarkClientAsNotFraud.groovy (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/contracts/shouldMarkClientAsNotFraud.json (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/contracts/shouldReturnFraudStats.groovy (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/contracts/shouldReturnFraudStats.json (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/contracts/shouldSendMessageWhenBookReturned.groovy (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/contracts/shouldSendMessageWhenBookReturned.json (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/contracts/shouldSendMessageWhenMessageReceived.groovy (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/contracts/shouldSendMessageWhenMessageReceived.json (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/contracts/shouldVerifyWhenBookWasDeleted.groovy (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/contracts/shouldVerifyWhenBookWasDeleted.json (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/pact/invalid_pact.json (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/pact/pact.json (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/pact/pact_509.json (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/pact/pact_v2.json (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/pact/pact_v3.json (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/pact/pact_v3_messaging.json (100%) rename spring-cloud-contract-tools/{spring-cloud-contract-spec-pact => spring-cloud-contract-pact}/src/test/resources/pact/pact_v3_unsupported_rule_logic.json (100%) delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/resources/META-INF/spring.factories delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldConvertAllMatchers.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldConvertAllMatchers.json create mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/mixed/invalid.json diff --git a/docs/src/main/asciidoc/verifier_contract.adoc b/docs/src/main/asciidoc/verifier_contract.adoc index 847ae76451..82d03388d0 100644 --- a/docs/src/main/asciidoc/verifier_contract.adoc +++ b/docs/src/main/asciidoc/verifier_contract.adoc @@ -1382,6 +1382,7 @@ org.springframework.cloud.contract.spec.ContractConverter=\ org.springframework.cloud.contract.verifier.converter.YamlContractConverter ---- +[[pact-converter]] ==== Pact Converter Spring Cloud Contract includes support for https://docs.pact.io/[Pact] representation of @@ -1675,3 +1676,76 @@ properties |1000 |Number of millis to wait between attempts to push the commits to `origin` |=== + +[[pact-stub-downloader]] +=== Using the Pact Stub Downloader + +Whenever the `repositoryRoot` starts with a Pact protocol +(starts with `pact://`), the stub downloader will try +to fetch the Pact contract definitions from the Pact Broker. +Whatever is set after `pact://` will be parsed as the Pact Broker URL. + +Either via environment variables, system properties, properties set +inside the plugin or contracts repository configuration you can +tweak the downloader's behaviour. Below you can find the list of +properties + +.SCM Stub Downloader properties +|=== +|Type of a property |Name of the property | Description +| +* `pactbroker.host` (plugin prop) +* `stubrunner.properties.pactbroker.host` (system prop) +* `STUBRUNNER_PROPERTIES_PACTBROKER_HOST` (env prop) +|Host from URL passed to `repositoryRoot` +|What is the URL of Pact Broker + +| +* `pactbroker.port` (plugin prop) +* `stubrunner.properties.pactbroker.port` (system prop) +* `STUBRUNNER_PROPERTIES_PACTBROKER_PORT` (env prop) +|Port from URL passed to `repositoryRoot` +|What is 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` +|What is 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 `+` +|What tags 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` +|What kind of authentication 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) +| +|Username used to connect to the Pact Broker + +| +* `pactbroker.auth.password` (plugin prop) +* `stubrunner.properties.pactbroker.auth.password` (system prop) +* `STUBRUNNER_PROPERTIES_PACTBROKER_AUTH_PASSWORD` (env prop) +| +|Password used to connect 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 will be a combination of `groupId:artifactId`. If `false`, just `artifactId` is used +|=== diff --git a/docs/src/main/asciidoc/verifier_faq.adoc b/docs/src/main/asciidoc/verifier_faq.adoc index fd1a8d0143..34ec2329dc 100644 --- a/docs/src/main/asciidoc/verifier_faq.adoc +++ b/docs/src/main/asciidoc/verifier_faq.adoc @@ -1,6 +1,5 @@ :introduction_url: https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/{branch} :samples_branch: 2.0.x -:samples_branch: 2.0.x == Spring Cloud Contract FAQ @@ -707,6 +706,195 @@ to find stub definitions and contracts. E.g. for `com.example:foo:1.0.0` the pat * Stub servers will be started and fed with mappings * Messaging definitions will be read and used in the messaging tests +=== Can I use the Pact Broker? + +When using http://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 one can fetch Pact files from the Pact Broker to generate +tests and stubs. + +As a prerequisite the Pact Converter and Pact Stub Downloader +are required. You have to add it via the `spring-cloud-contract-pact` dependency. +You can read more about it in the <> section. + +IMPORTANT: Pact follows the Consumer Contract convention. That means +that the Consumer creates the Pact definitions first, then +shares the files with the Producer. Those expectations are generated +from the Consumer's code and can break the Producer if the expectation +is not met. + +==== Pact Consumer + +The consumer uses Pact framework to generate Pact files. The +Pact files are sent to the Pact Broker. An example of such +setup can be found https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/{samples_branch}/consumer_pact[here]. + +==== Producer + +For the producer, to use the Pact files from the Pact Broker, we can reuse the +same mechanism we use for external contracts. We route Spring Cloud Contract +to use the Pact implementation via the URL that contains +the `pact://` protocol. It's enough to pass the URL to the +Pact Broker. + +.Maven +[source,xml,indent=0] +---- + + 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} + + + +---- + +.Gradle +[source,gradle,indent=0] +---- +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 will be downloaded from the Pact Broker +* Spring Cloud Contract will convert the Pact files into tests and stubs +* The JAR with the stubs gets automatically created as usual + +==== Pact Consumer (Producer Contract approach) + +In the scenario where you don't want to do Consumer Contract approach +(for every single consumer define the expectations) but you'd prefer +to do Producer Contracts (the producer provides the contracts and +publishes stubs), it's enough to use Spring Cloud Contract with +Stub Runner option. + +First, remember to add Stub Runner and Spring Cloud Contract Pact module +as test dependencies. + +.Maven +[source,xml,indent=0] +---- + + + + 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 + + +---- + +.Gradle +[source,gradle,indent=0] +---- +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, just pass the URL of the Pact Broker to `repositoryRoot`, prefixed +with `pact://` protocol. E.g. `pact://http://localhost:8085` + +[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 will be downloaded from the Pact Broker +* Spring Cloud Contract will convert the Pact files into stub definitions +* The stub servers will be started and fed with stubs + +For more information about Pact support you can go to +the <> section. + === How can I debug the request/response being sent by the generated tests client? The generated tests all boil down to RestAssured in some form or fashion which relies on https://hc.apache.org/httpcomponents-client-ga/[Apache HttpClient]. HttpClient has a facility called https://hc.apache.org/httpcomponents-client-ga/logging.html#Wire_Logging[wire logging] which logs the entire request and response to HttpClient. Spring Boot has a logging https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html[common application property] for doing this sort of thing, just add this to your application properties diff --git a/pom.xml b/pom.xml index 59d709b586..e761718110 100644 --- a/pom.xml +++ b/pom.xml @@ -123,6 +123,17 @@ + + au.com.dius + pact-jvm-provider-junit_2.12 + ${pact.version} + + + org.codehaus.groovy + groovy-all + + + au.com.dius pact-jvm-model diff --git a/samples/standalone/contracts/com/example/server/pom.xml b/samples/standalone/contracts/com/example/server/pom.xml index 5fd15bfe58..ef2b217265 100644 --- a/samples/standalone/contracts/com/example/server/pom.xml +++ b/samples/standalone/contracts/com/example/server/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.0.0.RELEASE diff --git a/samples/standalone/dsl/http-client/build.gradle b/samples/standalone/dsl/http-client/build.gradle index ba695f2378..d69fb30dcc 100644 --- a/samples/standalone/dsl/http-client/build.gradle +++ b/samples/standalone/dsl/http-client/build.gradle @@ -7,7 +7,7 @@ buildscript { maven { url "http://repo.spring.io/release" } } dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.BUILD-SNAPSHOT" + classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.RELEASE" } } diff --git a/samples/standalone/dsl/http-client/pom.xml b/samples/standalone/dsl/http-client/pom.xml index 66c0f0180c..865af6b071 100644 --- a/samples/standalone/dsl/http-client/pom.xml +++ b/samples/standalone/dsl/http-client/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.0.0.RELEASE diff --git a/samples/standalone/dsl/http-client/src/test/resources/application.yaml b/samples/standalone/dsl/http-client/src/test/resources/application.yaml index 21459f2953..79ba03fbb4 100644 --- a/samples/standalone/dsl/http-client/src/test/resources/application.yaml +++ b/samples/standalone/dsl/http-client/src/test/resources/application.yaml @@ -1,2 +1,3 @@ server: port: 6565 +logging.level.org.springframework.cloud.contract: DEBUG \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/build.gradle b/samples/standalone/dsl/http-server/build.gradle index d32d8adad0..805ea20906 100644 --- a/samples/standalone/dsl/http-server/build.gradle +++ b/samples/standalone/dsl/http-server/build.gradle @@ -10,7 +10,7 @@ buildscript { // end::repos[] dependencies { classpath 'org.codehaus.groovy:groovy-all:2.5.0-beta-1' - classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.BUILD-SNAPSHOT" + classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.RELEASE" classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${findProperty('verifierVersion') ?: verifierVersion}" } } diff --git a/samples/standalone/dsl/http-server/pom.xml b/samples/standalone/dsl/http-server/pom.xml index 2346a3e50e..961e4a5cdd 100644 --- a/samples/standalone/dsl/http-server/pom.xml +++ b/samples/standalone/dsl/http-server/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.0.0.RELEASE diff --git a/samples/standalone/messaging/stream-sink/build.gradle b/samples/standalone/messaging/stream-sink/build.gradle index 222e26cbba..14d9719529 100644 --- a/samples/standalone/messaging/stream-sink/build.gradle +++ b/samples/standalone/messaging/stream-sink/build.gradle @@ -7,7 +7,7 @@ buildscript { maven { url "http://repo.spring.io/release" } } dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.BUILD-SNAPSHOT" + classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.RELEASE" } } diff --git a/samples/standalone/messaging/stream-sink/pom.xml b/samples/standalone/messaging/stream-sink/pom.xml index 4b7c52dba8..899605ca93 100644 --- a/samples/standalone/messaging/stream-sink/pom.xml +++ b/samples/standalone/messaging/stream-sink/pom.xml @@ -14,7 +14,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.0.0.RELEASE diff --git a/samples/standalone/messaging/stream-source/build.gradle b/samples/standalone/messaging/stream-source/build.gradle index 0e2ced8d95..d0c9624c0a 100644 --- a/samples/standalone/messaging/stream-source/build.gradle +++ b/samples/standalone/messaging/stream-source/build.gradle @@ -7,7 +7,7 @@ buildscript { maven { url "http://repo.spring.io/release" } } dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.BUILD-SNAPSHOT" + classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.RELEASE" classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${findProperty('verifierVersion') ?: verifierVersion}" classpath "com.jayway.restassured:rest-assured:2.9.0" classpath "com.jayway.restassured:spring-mock-mvc:2.9.0" diff --git a/samples/standalone/messaging/stream-source/pom.xml b/samples/standalone/messaging/stream-source/pom.xml index 7013dd4c02..a34e547937 100644 --- a/samples/standalone/messaging/stream-source/pom.xml +++ b/samples/standalone/messaging/stream-source/pom.xml @@ -14,7 +14,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.0.0.RELEASE diff --git a/samples/standalone/pact/pact-http-client/build.gradle b/samples/standalone/pact/pact-http-client/build.gradle index 65cb923715..46debdf267 100644 --- a/samples/standalone/pact/pact-http-client/build.gradle +++ b/samples/standalone/pact/pact-http-client/build.gradle @@ -7,7 +7,7 @@ buildscript { maven { url "http://repo.spring.io/release" } } dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.BUILD-SNAPSHOT" + classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.RELEASE" } } @@ -39,7 +39,7 @@ dependencies { testCompile "org.springframework.cloud:spring-cloud-starter-contract-stub-runner" //tag::pact_dependency[] - testCompile "org.springframework.cloud:spring-cloud-contract-spec-pact" + testCompile "org.springframework.cloud:spring-cloud-contract-pact" testCompile 'au.com.dius:pact-jvm-model:3.5.13' //end::pact_dependency[] } diff --git a/samples/standalone/pact/pact-http-client/pom.xml b/samples/standalone/pact/pact-http-client/pom.xml index 322c055d53..0eeaec3700 100644 --- a/samples/standalone/pact/pact-http-client/pom.xml +++ b/samples/standalone/pact/pact-http-client/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.0.0.RELEASE @@ -46,7 +46,7 @@ org.springframework.cloud - spring-cloud-contract-spec-pact + spring-cloud-contract-pact test diff --git a/samples/standalone/pact/pact-http-server/build.gradle b/samples/standalone/pact/pact-http-server/build.gradle index 61ecf49bf1..8b2522b63a 100644 --- a/samples/standalone/pact/pact-http-server/build.gradle +++ b/samples/standalone/pact/pact-http-server/build.gradle @@ -7,10 +7,10 @@ buildscript { maven { url "http://repo.spring.io/release" } } dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.BUILD-SNAPSHOT" + classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.RELEASE" classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${findProperty('verifierVersion') ?: verifierVersion}" //tag::pact_dependency[] - classpath "org.springframework.cloud:spring-cloud-contract-spec-pact:${findProperty('verifierVersion') ?: verifierVersion}" + classpath "org.springframework.cloud:spring-cloud-contract-pact:${findProperty('verifierVersion') ?: verifierVersion}" classpath 'au.com.dius:pact-jvm-model:3.5.13' //end::pact_dependency[] } diff --git a/samples/standalone/pact/pact-http-server/pom.xml b/samples/standalone/pact/pact-http-server/pom.xml index bd4bfa4a71..f01e074236 100644 --- a/samples/standalone/pact/pact-http-server/pom.xml +++ b/samples/standalone/pact/pact-http-server/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.0.0.RELEASE @@ -77,7 +77,7 @@ org.springframework.cloud - spring-cloud-contract-spec-pact + spring-cloud-contract-pact ${spring-cloud-contract.version} diff --git a/samples/standalone/restdocs/http-client/build.gradle b/samples/standalone/restdocs/http-client/build.gradle index 7aa9774864..595170d5dc 100644 --- a/samples/standalone/restdocs/http-client/build.gradle +++ b/samples/standalone/restdocs/http-client/build.gradle @@ -7,7 +7,7 @@ buildscript { maven { url "http://repo.spring.io/release" } } dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.BUILD-SNAPSHOT" + classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.RELEASE" } } diff --git a/samples/standalone/restdocs/http-client/pom.xml b/samples/standalone/restdocs/http-client/pom.xml index 7a8f63d88c..9c2e052958 100644 --- a/samples/standalone/restdocs/http-client/pom.xml +++ b/samples/standalone/restdocs/http-client/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.0.0.RELEASE diff --git a/samples/standalone/restdocs/http-server/build.gradle b/samples/standalone/restdocs/http-server/build.gradle index 03a9dcee7b..b43b873218 100644 --- a/samples/standalone/restdocs/http-server/build.gradle +++ b/samples/standalone/restdocs/http-server/build.gradle @@ -10,7 +10,7 @@ buildscript { maven { url "http://repo.spring.io/plugins-staging-local/" } } dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.BUILD-SNAPSHOT" + classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.RELEASE" } } diff --git a/samples/standalone/restdocs/http-server/pom.xml b/samples/standalone/restdocs/http-server/pom.xml index 9ba39d36fc..987a7f0f17 100644 --- a/samples/standalone/restdocs/http-server/pom.xml +++ b/samples/standalone/restdocs/http-server/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.0.0.RELEASE diff --git a/samples/standalone/webclient/http-client/build.gradle b/samples/standalone/webclient/http-client/build.gradle index 16c83f2ffb..ff6ac87ed7 100644 --- a/samples/standalone/webclient/http-client/build.gradle +++ b/samples/standalone/webclient/http-client/build.gradle @@ -7,7 +7,7 @@ buildscript { maven { url "http://repo.spring.io/release" } } dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.BUILD-SNAPSHOT" + classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.RELEASE" } } diff --git a/samples/standalone/webclient/http-client/pom.xml b/samples/standalone/webclient/http-client/pom.xml index 4fe064e1de..e5853bd888 100644 --- a/samples/standalone/webclient/http-client/pom.xml +++ b/samples/standalone/webclient/http-client/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.0.0.RELEASE diff --git a/samples/standalone/webclient/http-server/build.gradle b/samples/standalone/webclient/http-server/build.gradle index c4d537bdd6..9a3b67476f 100644 --- a/samples/standalone/webclient/http-server/build.gradle +++ b/samples/standalone/webclient/http-server/build.gradle @@ -10,7 +10,7 @@ buildscript { maven { url "http://repo.spring.io/plugins-staging-local/" } } dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.BUILD-SNAPSHOT" + classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.RELEASE" } } diff --git a/samples/standalone/yml/http-client/build.gradle b/samples/standalone/yml/http-client/build.gradle index c549eaa389..4e4007f6a5 100644 --- a/samples/standalone/yml/http-client/build.gradle +++ b/samples/standalone/yml/http-client/build.gradle @@ -7,7 +7,7 @@ buildscript { maven { url "http://repo.spring.io/release" } } dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.BUILD-SNAPSHOT" + classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.RELEASE" } } diff --git a/samples/standalone/yml/http-client/pom.xml b/samples/standalone/yml/http-client/pom.xml index 79d208b244..c0bcaecc8c 100644 --- a/samples/standalone/yml/http-client/pom.xml +++ b/samples/standalone/yml/http-client/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.0.0.RELEASE diff --git a/samples/standalone/yml/http-server/build.gradle b/samples/standalone/yml/http-server/build.gradle index cac9d91c3a..1c14b90671 100644 --- a/samples/standalone/yml/http-server/build.gradle +++ b/samples/standalone/yml/http-server/build.gradle @@ -9,7 +9,7 @@ buildscript { } // end::repos[] dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.BUILD-SNAPSHOT" + classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.RELEASE" classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${findProperty('verifierVersion') ?: verifierVersion}" } } diff --git a/samples/standalone/yml/http-server/pom.xml b/samples/standalone/yml/http-server/pom.xml index c700394c44..87bb1b0543 100644 --- a/samples/standalone/yml/http-server/pom.xml +++ b/samples/standalone/yml/http-server/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.0.0.RELEASE diff --git a/spring-cloud-contract-dependencies/pom.xml b/spring-cloud-contract-dependencies/pom.xml index ad36d14611..c88b1fa776 100644 --- a/spring-cloud-contract-dependencies/pom.xml +++ b/spring-cloud-contract-dependencies/pom.xml @@ -43,7 +43,7 @@ org.springframework.cloud - spring-cloud-contract-spec-pact + spring-cloud-contract-pact ${project.version} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java index 366eb6986a..2206af6d9b 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java @@ -255,7 +255,7 @@ public class AetherStubDownloader implements StubDownloader { } private static File unpackStubJarToATemporaryFolder(URI stubJarUri) { - File tmpDirWhereStubsWillBeUnzipped = TemporaryFileStorage.unpackStubJarToATemporaryFolder(TEMP_DIR_PREFIX); + File tmpDirWhereStubsWillBeUnzipped = TemporaryFileStorage.createTempDir(TEMP_DIR_PREFIX); log.info("Unpacking stub from JAR [URI: " + stubJarUri + "]"); unzipTo(new File(stubJarUri), tmpDirWhereStubsWillBeUnzipped); TemporaryFileStorage.add(tmpDirWhereStubsWillBeUnzipped); diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ContractDownloader.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ContractDownloader.java index 6f34f9fec6..daa388dc84 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ContractDownloader.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ContractDownloader.java @@ -81,11 +81,17 @@ public class ContractDownloader { } else { log.info("Will pick a pattern from group id and artifact id"); if (hasGavInPath(contractsDirectory)) { + if (log.isDebugEnabled()) { + log.debug("Group & artifact in path"); + } contractsDirectory = contractsSubDirIfPresent(contractsDirectory); - // we're already under proper folder (for the given version) + // we're already under proper folder (for the given group and artifact) pattern = fileToPattern(contractsDirectory); includedAntPattern = "**/"; } else { + if (log.isDebugEnabled()) { + log.debug("No group & artifact in path"); + } pattern = groupArtifactToPattern(contractsDirectory); includedAntPattern = wrapWithAntPattern(slashSeparatedGroupId() + "/" + this.projectArtifactId); } diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ScmStubDownloaderBuilder.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ScmStubDownloaderBuilder.java index 3bb82cf4cc..4d1bf8d4e5 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ScmStubDownloaderBuilder.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ScmStubDownloaderBuilder.java @@ -122,7 +122,7 @@ class GitContractsRepo { File file = CACHED_LOCATIONS.get(repo); GitStubDownloaderProperties properties = new GitStubDownloaderProperties(repo, this.options); if (file == null) { - File tmpDirWhereStubsWillBeUnzipped = TemporaryFileStorage.unpackStubJarToATemporaryFolder(TEMP_DIR_PREFIX); + File tmpDirWhereStubsWillBeUnzipped = TemporaryFileStorage.createTempDir(TEMP_DIR_PREFIX); GitRepo gitRepo = new GitRepo(tmpDirWhereStubsWillBeUnzipped, properties); file = gitRepo.cloneProject(properties.url); gitRepo.checkout(file, properties.branch); diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubConfiguration.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubConfiguration.java index d2aad87027..36e070ad56 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubConfiguration.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubConfiguration.java @@ -24,7 +24,7 @@ import org.springframework.util.StringUtils; */ public class StubConfiguration { private static final String STUB_COLON_DELIMITER = ":"; - private static final String DEFAULT_VERSION = "+"; + static final String DEFAULT_VERSION = "+"; public static final String DEFAULT_CLASSIFIER = "stubs"; final String groupId; diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerPropertyUtils.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerPropertyUtils.java index 2f50a7e5f4..6c4f301436 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerPropertyUtils.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerPropertyUtils.java @@ -46,6 +46,15 @@ class StubRunnerPropertyUtils { return StringUtils.hasText(value) && Boolean.parseBoolean(value); } + /** + * For options, system props and env vars returns {@code true} + * when property is set + */ + static boolean hasProperty(Map options, String propName) { + String value = getProperty(options, propName); + return StringUtils.hasText(value); + } + /** * Tries to pick a value from options, for Env vars takes the prop name, converts * dots to underscores and applies upper case diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/TemporaryFileStorage.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/TemporaryFileStorage.java index d5ec0d7efa..abd2735297 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/TemporaryFileStorage.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/TemporaryFileStorage.java @@ -97,7 +97,7 @@ class TemporaryFileStorage { } } - static File unpackStubJarToATemporaryFolder(String tempDirPrefix) { + static File createTempDir(String tempDirPrefix) { try { return createTempDirectory(tempDirPrefix) .toFile(); diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerPropertyUtilsSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerPropertyUtilsSpec.groovy index 88ce54e71d..9edcc25689 100644 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerPropertyUtilsSpec.groovy +++ b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerPropertyUtilsSpec.groovy @@ -82,6 +82,34 @@ class StubRunnerPropertyUtilsSpec extends Specification { "foo.bar-baz" | null | "" | "bc" | "bc" | "stubrunner.properties.foo.bar-baz" | "STUBRUNNER_PROPERTIES_FOO_BAR_BAZ" } + @RestoreSystemProperties + def "should return [#expectedResult] when prop is set for [#queriedProp] and system is [#systemProperty] and env [#envVariable]"() { + given: + def sysProp = systemProperty + def envVar = envVariable + PropertyFetcher fetcher = new PropertyFetcher() { + @Override + String systemProp(String prop) { + return sysProp + } + + @Override + String envVar(String prop) { + return envVar + } + } + StubRunnerPropertyUtils.FETCHER = fetcher + expect: + expectedResult == StubRunnerPropertyUtils.hasProperty(map, queriedProp) + where: + queriedProp | map | systemProperty | envVariable | expectedResult + "foo.bar-baz" | ["foo.bar-baz": "faz"] | "ab" | "bc" | true + "foo.bar-baz" | [:] | "ab" | "bc" | true + "foo.bar-baz" | [:] | "" | "bc" | true + "foo.bar-baz" | null | "" | "bc" | true + "foo.bar-baz" | null | null | null | false + } + def cleanupSpec() { StubRunnerPropertyUtils.FETCHER = new PropertyFetcher() } diff --git a/spring-cloud-contract-tools/pom.xml b/spring-cloud-contract-tools/pom.xml index 1f2a7ae820..0f54ab7bc3 100644 --- a/spring-cloud-contract-tools/pom.xml +++ b/spring-cloud-contract-tools/pom.xml @@ -19,7 +19,7 @@ spring-cloud-contract-converters - spring-cloud-contract-spec-pact + spring-cloud-contract-pact spring-cloud-contract-maven-plugin spring-cloud-contract-gradle-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 a18e5c6ff9..9911b7e4db 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 @@ -415,7 +415,7 @@ org.springframework.cloud - spring-cloud-contract-spec-pact + spring-cloud-contract-pact test diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloader.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloader.java index db8e82283b..338ba8b5ab 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloader.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloader.java @@ -90,7 +90,7 @@ class MavenContractsDownloader { contractDownloader().updatePropertiesWithInclusion(downloadedContractsDir, config); return downloadedContractsDir; } else if (shouldDownloadContracts()) { - this.log.info("Download dependency is provided - will download contract jars"); + this.log.info("Download dependency is provided - will retrieve contracts from a remote location"); File downloadedContracts = contractDownloader().unpackedDownloadedContracts(config); this.project.getProperties().setProperty(CONTRACTS_DIRECTORY_PROP, downloadedContracts.getAbsolutePath()); return downloadedContracts; 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 index 0903e15de3..2027b26d9a 100644 --- 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 @@ -46,7 +46,7 @@ org.springframework.cloud - spring-cloud-contract-spec-pact + spring-cloud-contract-pact ${spring.cloud.contract.version} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-pact/pom.xml similarity index 71% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/pom.xml rename to spring-cloud-contract-tools/spring-cloud-contract-pact/pom.xml index f557aeb13d..6b5ccca6d9 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/pom.xml +++ b/spring-cloud-contract-tools/spring-cloud-contract-pact/pom.xml @@ -8,10 +8,10 @@ 2.0.0.BUILD-SNAPSHOT .. - spring-cloud-contract-spec-pact + spring-cloud-contract-pact jar - Spring Cloud Contract Spec Pact - Spring Cloud Contract Spec Pact + Spring Cloud Contract Pact + Spring Cloud Contract Pact org.springframework @@ -19,7 +19,11 @@ org.springframework.cloud - spring-cloud-contract-verifier + spring-cloud-contract-converters + + + org.springframework.cloud + spring-cloud-contract-stub-runner org.springframework.boot @@ -37,6 +41,10 @@ au.com.dius pact-jvm-consumer-java8_2.12 + + au.com.dius + pact-jvm-provider-junit_2.12 + org.spockframework spock-core @@ -52,6 +60,11 @@ spock-global-unroll test + + org.springframework.cloud + spring-cloud-contract-wiremock + test + @@ -62,8 +75,13 @@ addSources + addTestSources + generateStubs compile + testGenerateStubs testCompile + removeStubs + removeTestStubs diff --git a/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/stubrunner/PactStubDownloaderBuilder.java b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/stubrunner/PactStubDownloaderBuilder.java new file mode 100644 index 0000000000..3134ce16e2 --- /dev/null +++ b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/stubrunner/PactStubDownloaderBuilder.java @@ -0,0 +1,376 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.contract.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.model.Pact; +import au.com.dius.pact.model.PactSpecVersion; +import au.com.dius.pact.provider.junit.loader.PactBroker; +import au.com.dius.pact.provider.junit.loader.PactBrokerAuth; +import au.com.dius.pact.provider.junit.loader.PactBrokerLoader; +import au.com.dius.pact.provider.junit.loader.PactLoader; +import au.com.dius.pact.provider.junit.sysprops.SystemPropertyResolver; +import au.com.dius.pact.provider.junit.sysprops.ValueResolver; +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.jetbrains.annotations.NotNull; +import org.springframework.cloud.contract.spec.Contract; +import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; +import org.springframework.cloud.contract.verifier.converter.StubGenerator; +import org.springframework.cloud.contract.verifier.converter.StubGeneratorProvider; +import org.springframework.cloud.contract.verifier.file.ContractMetadata; +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.util.StringUtils; + +/** + * Allows downloading of Pact files from the Pact Broker. + * + * @author Marcin Grzejszczak + * @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 + */ + 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.isEmpty(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 final StubRunnerOptions stubRunnerOptions; + private final boolean deleteStubsAfterTest; + private final ObjectMapper objectMapper; + + private static final String PROVIDER_NAME_WITH_GROUP_ID = "pactbroker.provider-name-with-group-id"; + + 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()) { + 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"); + } + StubGeneratorProvider provider = new StubGeneratorProvider(); + Collection stubGenerators = provider + .converterForName(ARTIFICIAL_NAME_ENDING_WITH_GROOVY); + if (log.isDebugEnabled()) { + log.debug("Found following matching stub generators " + stubGenerators); + } + for (StubGenerator stubGenerator : stubGenerators) { + Map map = stubGenerator + .convertContents(file.getName(), + new ContractMetadata(file.toPath(), false, + contracts.size(), null, contracts)); + for (Map.Entry entry : map.entrySet()) { + String value = entry.getValue(); + File mapping = new File(mappingsFolder, + StringUtils.stripFilenameExtension(file.getName()) + "_" + + Math.abs(entry.getKey().hashCode()) + ".json"); + storeFile(mapping.toPath(), value.getBytes()); + } + } + } + + private void storeFile(Path path, byte[] contents) { + try { + Files.write(path, contents); + if (log.isDebugEnabled()) { + log.debug("Stored file [" + path.toString() + "]"); + } + } + 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(); + } + + @NotNull PactLoader pactBrokerLoader(ValueResolver resolver, + List tags) throws IOException { + Resource repo = this.stubRunnerOptions.getStubRepositoryRoot(); + String schemeSpecificPart = schemeSpecificPart(repo.getURI()); + URI pactBrokerUrl = URI.create(schemeSpecificPart); + return new PactBrokerLoader(new PactBroker() { + + @Override public Class annotationType() { + return PactBroker.class; + } + + @Override public String host() { + return resolver.resolveValue("pactbroker.host:" + pactBrokerUrl.getHost()); + } + + @Override public String port() { + return resolver.resolveValue("pactbroker.port:" + pactBrokerUrl.getPort()); + } + + @Override public String protocol() { + return resolver.resolveValue("pactbroker.protocol:" + pactBrokerUrl.getScheme()); + } + + @Override public String[] tags() { + return tags.toArray(new String[0]); + } + + @Override public boolean failIfNoPactsFound() { + return true; + } + + @Override public PactBrokerAuth authentication() { + return new PactBrokerAuth() { + @Override public Class annotationType() { + return PactBrokerAuth.class; + } + + @Override public String scheme() { + return resolver.resolveValue("pactbroker.auth.scheme:basic"); + } + + @Override public String username() { + return resolver.resolveValue("pactbroker.auth.username:"); + } + + @Override public String password() { + return resolver.resolveValue("pactbroker.auth.password:"); + } + }; + } + + @Override public Class valueResolver() { + return SystemPropertyResolver.class; + } + }); + } + + private String schemeSpecificPart(URI uri) { + String part = uri.getSchemeSpecificPart(); + if (StringUtils.isEmpty(part)) { + return part; + } + return part.startsWith("//") ? part.substring(2) : part; + } + + @NotNull 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 = new SystemPropertyResolver(); + StubRunnerOptions options; + + FromPropsThenFromSysEnv(StubRunnerOptions options) { + this.options = options; + } + + @Override public String resolveValue(String expression) { + 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); + } + + @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); + } +} + +// 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; + } +} \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/BodyConverter.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/BodyConverter.groovy similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/BodyConverter.groovy rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/BodyConverter.groovy diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/MatchingRulesConverter.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/MatchingRulesConverter.groovy similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/MatchingRulesConverter.groovy rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/MatchingRulesConverter.groovy diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/MessagePactCreator.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/MessagePactCreator.groovy similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/MessagePactCreator.groovy rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/MessagePactCreator.groovy diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/MessagingSCContractCreator.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/MessagingSCContractCreator.groovy similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/MessagingSCContractCreator.groovy rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/MessagingSCContractCreator.groovy diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverter.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverter.groovy similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverter.groovy rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverter.groovy diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/RequestResponsePactCreator.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/RequestResponsePactCreator.groovy similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/RequestResponsePactCreator.groovy rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/RequestResponsePactCreator.groovy diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/RequestResponseSCContractCreator.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/RequestResponseSCContractCreator.groovy similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/RequestResponseSCContractCreator.groovy rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/RequestResponseSCContractCreator.groovy diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/ValueGeneratorConverter.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/ValueGeneratorConverter.groovy similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/ValueGeneratorConverter.groovy rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/groovy/org/springframework/cloud/contract/verifier/spec/pact/ValueGeneratorConverter.groovy 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 new file mode 100644 index 0000000000..4624a09077 --- /dev/null +++ b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/main/resources/META-INF/spring.factories @@ -0,0 +1,5 @@ +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 \ No newline at end of file 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 new file mode 100644 index 0000000000..104a9cc35a --- /dev/null +++ b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/groovy/org/springframework/cloud/contract/stubrunner/PactStubDownloaderBuilderSpec.groovy @@ -0,0 +1,114 @@ +package org.springframework.cloud.contract.stubrunner + +import java.nio.file.Files + +import au.com.dius.pact.model.Pact +import au.com.dius.pact.model.PactSource +import au.com.dius.pact.provider.junit.loader.PactLoader +import au.com.dius.pact.provider.junit.sysprops.ValueResolver +import com.github.tomakehurst.wiremock.stubbing.StubMapping +import org.jetbrains.annotations.NotNull +import spock.lang.Specification + +import org.springframework.cloud.contract.spec.Contract +import org.springframework.cloud.contract.verifier.spec.pact.PactContractConverter + +/** + * @author Marcin Grzejszczak + */ +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) { + @NotNull @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) + // } + // } +} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-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 similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverterSpec.groovy rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverterSpec.groovy diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldConvertAllGenerators.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldConvertAllGenerators.groovy similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldConvertAllGenerators.groovy rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldConvertAllGenerators.groovy diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldConvertAllGenerators.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldConvertAllGenerators.json similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldConvertAllGenerators.json rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldConvertAllGenerators.json diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldMarkClientAsFraud.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsFraud.groovy similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldMarkClientAsFraud.groovy rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsFraud.groovy diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldMarkClientAsFraud.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsFraud.json similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldMarkClientAsFraud.json rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsFraud.json diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.groovy similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.groovy rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.groovy diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.json similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.json rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldMarkClientAsNotFraud.json diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldReturnFraudStats.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldReturnFraudStats.groovy similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldReturnFraudStats.groovy rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldReturnFraudStats.groovy diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldReturnFraudStats.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldReturnFraudStats.json similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldReturnFraudStats.json rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldReturnFraudStats.json diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldSendMessageWhenBookReturned.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldSendMessageWhenBookReturned.groovy similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldSendMessageWhenBookReturned.groovy rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldSendMessageWhenBookReturned.groovy diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldSendMessageWhenBookReturned.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldSendMessageWhenBookReturned.json similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldSendMessageWhenBookReturned.json rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldSendMessageWhenBookReturned.json diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldSendMessageWhenMessageReceived.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldSendMessageWhenMessageReceived.groovy similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldSendMessageWhenMessageReceived.groovy rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldSendMessageWhenMessageReceived.groovy diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldSendMessageWhenMessageReceived.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldSendMessageWhenMessageReceived.json similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldSendMessageWhenMessageReceived.json rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldSendMessageWhenMessageReceived.json diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldVerifyWhenBookWasDeleted.groovy b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldVerifyWhenBookWasDeleted.groovy similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldVerifyWhenBookWasDeleted.groovy rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldVerifyWhenBookWasDeleted.groovy diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldVerifyWhenBookWasDeleted.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldVerifyWhenBookWasDeleted.json similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldVerifyWhenBookWasDeleted.json rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/contracts/shouldVerifyWhenBookWasDeleted.json diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/pact/invalid_pact.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/invalid_pact.json similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/pact/invalid_pact.json rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/invalid_pact.json diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/pact/pact.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact.json similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/pact/pact.json rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact.json diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/pact/pact_509.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_509.json similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/pact/pact_509.json rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_509.json diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/pact/pact_v2.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v2.json similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/pact/pact_v2.json rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v2.json diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/pact/pact_v3.json b/spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v3.json similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/pact/pact_v3.json rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v3.json diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-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 similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/pact/pact_v3_messaging.json rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v3_messaging.json diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-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 similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/pact/pact_v3_unsupported_rule_logic.json rename to spring-cloud-contract-tools/spring-cloud-contract-pact/src/test/resources/pact/pact_v3_unsupported_rule_logic.json diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/resources/META-INF/spring.factories b/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 640c7019cf..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.cloud.contract.spec.ContractConverter=\ -org.springframework.cloud.contract.verifier.spec.pact.PactContractConverter diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldConvertAllMatchers.groovy b/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldConvertAllMatchers.groovy deleted file mode 100644 index 38cfee255e..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldConvertAllMatchers.groovy +++ /dev/null @@ -1,68 +0,0 @@ -package contracts - -org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - url '/' - 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', - someNullValue: null - ]) - headers { - contentType('application/json') - header("Some-Header", $(c(regex('[a-zA-Z]{9}')), p('someValue'))) - header("Header-Without-Matcher", 'someValue') - } - bodyMatchers { - jsonPath('$.someInteger', byRegex(anInteger())) - jsonPath('$.someDecimal', byRegex(aDouble())) - jsonPath('$.someHex', byRegex('[a-fA-F0-9]+')) - jsonPath('$.someAlphaNumeric', byRegex(alphaNumeric())) - jsonPath('$.someUUID', byRegex(uuid())) - jsonPath('$.someDate', byDate()) - jsonPath('$.someTime', byTime()) - jsonPath('$.someDateTime', byTimestamp()) - jsonPath('$.someBoolean', byRegex(anyBoolean())) - } - } - response { - status OK() - 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 - ]) - headers { - contentType('application/json') - header("Some-Header", $(c('someValue'), p(regex('[a-zA-Z]{9}')))) - header("Header-Without-Matcher", 'someValue') - } - bodyMatchers { - jsonPath('$.someInteger', byRegex(anInteger())) - jsonPath('$.someDecimal', byRegex(aDouble())) - jsonPath('$.someHex', byRegex('[a-fA-F0-9]+')) - jsonPath('$.someAlphaNumeric', byRegex(alphaNumeric())) - jsonPath('$.someUUID', byRegex(uuid())) - jsonPath('$.someDate', byDate()) - jsonPath('$.someTime', byTime()) - jsonPath('$.someDateTime', byTimestamp()) - jsonPath('$.someBoolean', byRegex(anyBoolean())) - jsonPath('$.someNullValue', byNull()) - } - } -} \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldConvertAllMatchers.json b/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldConvertAllMatchers.json deleted file mode 100644 index d44a56f190..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/resources/contracts/shouldConvertAllMatchers.json +++ /dev/null @@ -1,276 +0,0 @@ -{ - "provider": { - "name": "Provider" - }, - "consumer": { - "name": "Consumer" - }, - "interactions": [ - { - "description": "", - "request": { - "method": "POST", - "path": "/", - "headers": { - "Content-Type": "application/json", - "Header-Without-Matcher": "someValue", - "Some-Header": "someValue" - }, - "body": { - "someHex": "DEADC0DE", - "someTime": "13:37:00", - "someNullValue": null, - "someInteger": 1234567890, - "someBoolean": "true", - "someDate": "2018-03-26", - "someUUID": "00000000-0000-0000-0000-000000000000", - "someDecimal": 123.123, - "someAlphaNumeric": "Some alpha numeric string with 1234567890", - "someDateTime": "2018-03-26 13:37:00" - }, - "matchingRules": { - "header": { - "Content-Type": { - "matchers": [ - { - "match": "regex", - "regex": "application/json.*" - } - ], - "combine": "AND" - }, - "Some-Header": { - "matchers": [ - { - "match": "regex", - "regex": "[a-zA-Z]{9}" - } - ], - "combine": "AND" - } - }, - "body": { - "$.someInteger": { - "matchers": [ - { - "match": "integer" - } - ], - "combine": "AND" - }, - "$.someDecimal": { - "matchers": [ - { - "match": "decimal" - } - ], - "combine": "AND" - }, - "$.someHex": { - "matchers": [ - { - "match": "regex", - "regex": "[a-fA-F0-9]+" - } - ], - "combine": "AND" - }, - "$.someAlphaNumeric": { - "matchers": [ - { - "match": "regex", - "regex": "[a-zA-Z0-9]+" - } - ], - "combine": "AND" - }, - "$.someUUID": { - "matchers": [ - { - "match": "regex", - "regex": "[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}" - } - ], - "combine": "AND" - }, - "$.someDate": { - "matchers": [ - { - "match": "date", - "date": "yyyy-MM-dd" - } - ], - "combine": "AND" - }, - "$.someTime": { - "matchers": [ - { - "match": "time", - "time": "HH:mm:ss" - } - ], - "combine": "AND" - }, - "$.someDateTime": { - "matchers": [ - { - "match": "timestamp", - "timestamp": "yyyy-MM-dd HH:mm:ssZZZ" - } - ], - "combine": "AND" - }, - "$.someBoolean": { - "matchers": [ - { - "match": "regex", - "regex": "(true|false)" - } - ], - "combine": "AND" - } - } - } - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json", - "Header-Without-Matcher": "someValue", - "Some-Header": "someValue" - }, - "body": { - "someHex": "DEADC0DE", - "someTime": "13:37:00", - "someInteger": 1234567890, - "someBoolean": "true", - "someRegex": 1234567890, - "someDate": "2018-03-26", - "someUUID": "00000000-0000-0000-0000-000000000000", - "someDecimal": 123.123, - "someAlphaNumeric": "Some alpha numeric string with 1234567890", - "someDateTime": "2018-03-26 13:37:00" - }, - "matchingRules": { - "header": { - "Content-Type": { - "matchers": [ - { - "match": "regex", - "regex": "application/json.*" - } - ], - "combine": "AND" - }, - "Some-Header": { - "matchers": [ - { - "match": "regex", - "regex": "[a-zA-Z]{9}" - } - ], - "combine": "AND" - } - }, - "body": { - "$.someInteger": { - "matchers": [ - { - "match": "integer" - } - ], - "combine": "AND" - }, - "$.someDecimal": { - "matchers": [ - { - "match": "decimal" - } - ], - "combine": "AND" - }, - "$.someHex": { - "matchers": [ - { - "match": "regex", - "regex": "[a-fA-F0-9]+" - } - ], - "combine": "AND" - }, - "$.someAlphaNumeric": { - "matchers": [ - { - "match": "regex", - "regex": "[a-zA-Z0-9]+" - } - ], - "combine": "AND" - }, - "$.someUUID": { - "matchers": [ - { - "match": "regex", - "regex": "[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}" - } - ], - "combine": "AND" - }, - "$.someDate": { - "matchers": [ - { - "match": "date", - "date": "yyyy-MM-dd" - } - ], - "combine": "AND" - }, - "$.someTime": { - "matchers": [ - { - "match": "time", - "time": "HH:mm:ss" - } - ], - "combine": "AND" - }, - "$.someDateTime": { - "matchers": [ - { - "match": "timestamp", - "timestamp": "yyyy-MM-dd HH:mm:ssZZZ" - } - ], - "combine": "AND" - }, - "$.someBoolean": { - "matchers": [ - { - "match": "regex", - "regex": "(true|false)" - } - ], - "combine": "AND" - }, - "$.someNullValue": { - "matchers": [ - { - "match": "null" - } - ], - "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-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/TestGenerator.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/TestGenerator.groovy index 1ddc638d68..df4ef6d63e 100755 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/TestGenerator.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/TestGenerator.groovy @@ -21,6 +21,8 @@ import java.nio.file.Path import java.util.concurrent.atomic.AtomicInteger import groovy.transform.PackageScope +import org.apache.commons.logging.Log +import org.apache.commons.logging.LogFactory import wiremock.com.google.common.collect.ListMultimap import org.springframework.cloud.contract.spec.ContractVerifierException @@ -42,6 +44,7 @@ import static org.springframework.cloud.contract.verifier.util.NamesUtil.toLastD */ class TestGenerator { + private static final Log log = LogFactory.getLog(TestGenerator) private static final String DEFAULT_CLASS_PREFIX = "ContractVerifier" private static final String DEFAULT_TEST_PACKAGE = "org.springframework.cloud.contract.verifier.tests" @@ -111,6 +114,9 @@ class TestGenerator { private void processIncludedDirectory( final String includedDirectoryRelativePath, Collection contracts, final String basePackageNameForClass) { + if (log.isDebugEnabled()) { + log.debug("Collected contracts with metadata ${contracts}") + } if (contracts.size()) { def className = afterLast(includedDirectoryRelativePath.toString(), File.separator) + resolveNameSuffix() def convertedClassName = convertIllegalPackageChars(className) diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScanner.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScanner.groovy index 494695e7aa..8ca4be4e25 100755 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScanner.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScanner.groovy @@ -87,7 +87,7 @@ class ContractFileScanner { * and try to convert via pluggable Contract Converters any possible contracts */ private void appendRecursively(File baseDir, ListMultimap result) { - List converters = SpringFactoriesLoader.loadFactories(ContractConverter, null) + List converters = converters() if (log.isTraceEnabled()) { log.trace("Found the following contract converters ${converters}") } @@ -122,13 +122,18 @@ class ContractFileScanner { } } + protected List converters() { + return SpringFactoriesLoader.loadFactories(ContractConverter, null) + } + private void addContractToTestGeneration(List converters, ListMultimap result, File[] files, File file, int index) { boolean converted = false if (!file.isDirectory()) { for (ContractConverter converter : converters) { - if (converter.isAccepted(file)) { - addContractToTestGeneration(result, files, file, index, converter.convertFrom(file)) + Collection contracts = tryConvert(converter, file) + if (contracts) { + addContractToTestGeneration(result, files, file, index, contracts) converted = true break } @@ -142,6 +147,21 @@ class ContractFileScanner { } } + private Collection tryConvert(ContractConverter converter, File file) { + boolean accepted = converter.isAccepted(file) + if (!accepted) { + return null + } + try { + return converter.convertFrom(file) + } catch (Exception e) { + if (log.isDebugEnabled()) { + log.debug("Exception occurred while trying to convert the file", e) + } + return null + } + } + private void addContractToTestGeneration(ListMultimap result, File[] files, File file, int index, Collection convertedContract) { Path path = file.toPath() @@ -154,6 +174,9 @@ class ContractFileScanner { files.size(), order, convertedContract) if (log.isDebugEnabled()) { log.debug("Creating a contract entry for path [" + path + "] and metadata [" + metadata + "]") + } + if (convertedContract) { + } result.put(parent, metadata) } diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScannerSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScannerSpec.groovy index 88388415b6..d4ee0cdf48 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScannerSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScannerSpec.groovy @@ -21,6 +21,9 @@ import spock.lang.Specification import java.nio.file.Path +import org.springframework.cloud.contract.spec.Contract +import org.springframework.cloud.contract.spec.ContractConverter + /** * @author Jakub Kubrynski, codearte.io */ @@ -77,7 +80,27 @@ class ContractFileScannerSpec extends Specification { def "should find contract files with converters"() { given: File baseDir = new File(this.getClass().getResource("/directory/with/mixed").toURI()) - ContractFileScanner scanner = new ContractFileScanner(baseDir, null, null) + ContractFileScanner scanner = new ContractFileScanner(baseDir, null, null) { + @Override + protected List converters() { + return [new ContractConverter() { + @Override + boolean isAccepted(File file) { + return file.name.endsWith(".json") + } + + @Override + Collection convertFrom(File file) { + throw new RuntimeException("boom") + } + + @Override + Object convertTo(Collection contract) { + throw new RuntimeException("boom") + } + }] + } + } when: ListMultimap result = scanner.findContracts() then: diff --git a/spring-cloud-contract-verifier/src/test/resources/directory/with/mixed/invalid.json b/spring-cloud-contract-verifier/src/test/resources/directory/with/mixed/invalid.json new file mode 100644 index 0000000000..92da92f7da --- /dev/null +++ b/spring-cloud-contract-verifier/src/test/resources/directory/with/mixed/invalid.json @@ -0,0 +1,23 @@ +{ + "request": { + "method": "PUT", + "url": "/loanApplication", + "headers": { + "Content-Type": { + "equalTo": "application/vnd.loanapplicationservice.v1+json" + } + }, + "bodyPatterns": [ + { + "matches": "\\{\"clientPesel\":\"1234567890\",\"loanAmount\":123.123\\}" + } + ] + }, + "response": { + "status": 200, + "body": "{\"loanApplicationStatus\":\"LOAN_APPLIED\",\"loanApplicationId\":\"${123123123:$anyInt($it)}\",\"rejectionReason\":null}", + "headers": { + "Content-Type": "application/vnd.loanapplicationservice.v1+json" + } + } +} \ No newline at end of file diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockSpring.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockSpring.java index 49ceac2840..bb60a18369 100644 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockSpring.java +++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockSpring.java @@ -66,8 +66,7 @@ public abstract class WireMockSpring { } initialized = true; } - WireMockConfiguration config = new WireMockConfiguration(); - return config; + return new WireMockConfiguration(); } }